装饰模式--Decorator Pattern

  模拟场景:张三今天有个约会,但是他很苦恼,因为他在纠结今天不知道要穿什么衣服去约会。假如张三现在身上只穿着内衣裤。那他在挑选衣服进行装饰自己的时候,要怎么实现呢?

  分析:不用说,肯定会有一个Person类。现在我们用最简单的方式来完成。

Person

 1 package com.zqz.dp.decorator;
 2 /**
 3  * @author Qin person类,来保存张三的属性
 4  */
 5 public class Person {
 6     private String name; // person name
 7     public Person(String name) { // 构造方法赋值
 8         this.name = name;
 9     }
10     public void show() { // 展示方法
11         System.out.print(" 装扮的" + this.name);
12     }
13     public void wearA(){
14         System.out.print("A服饰 ");
15     }
16     public void wearB(){
17         System.out.print("B裤衩 ");
18     }
19 }

Client

 1 package com.zqz.dp.decorator;
 2 /**
 3  * @author Qin
 4  * 场景类
 5  */
 6 public class Client {
 7     public static void main(String[] args) {
 8         Person per=new Person("张三");
 9         System.out.println("------第一种装扮-------");
10         per.wearA();    //张三装饰自己
11         per.wearB();    //张三装饰自己
12         per.show();    //张三展示自己
13     }
14 }

  以上确实完成了功能,但是耦合度很高。现在假设张三在去约会之前要先打电话给MM,跟她更改会面的时候,要怎么做呢?

  很明显,以现在的模式的话肯定要修改Person类和Client端。每次添加一个操作就要修改Person,明显违背了开闭原则,要记住,在开发中,允许对类进行拓展,但是对修改时关闭的。当然所有类要做到全无修改是不实际的。但是要让类的修改达到最少。

  先考虑下,我们现在是要对类进行装饰,也就是说要在类前后进行一些操作。咦,这不是可以用静态代理来实现吗?

其实装饰模式就是代理模式的一个扩展,只是代理和装饰两者负责的范畴是不一样的。简单的说,代理模式专注的是对对象访问的控制AOP中添加权限处理的操作就是进行控制,只有有权限的才可以进行执行,没有权限的无法执行。而装饰模式专注的是为对象进行装饰,也就是说为对象添加逻辑。

  其实现在就涉及了一个问题:添加逻辑的方法

  也就是说现在需要对某个类添加一些操作,那该如何做呢?有这么几种方法:

  1、  在原来的代码中补充,违背了开闭原则,如上面的操作(不建议使用)。

  2、  继承原来的类,在类执行之前添加操作。这就是我们要说的装饰模式

  3、  使用接口,和继承是一样的道理,不过接口实现会方便点。

  现在我们修改下需求,现在张三正在哼着歌,准备要去约会。突然间他发现自己的装扮有点乱,还发现要去约会的地点人满为患;所以这个时候张三先去打扮下,出门后给MM打电话更改约会地点。要如何进行装饰呢?

  既然装饰是代理的一种体现,那在这里也不废话了,只是这个用的是继承的操作。

Person

 1 package com.zqz.dp.decorator;
 2 /**
 3  * @author Qin
 4  * person类,来保存张三的属性
 5  */
 6 public class Person {
 7     @SuppressWarnings("unused")
 8     private String name; // person name
 9     public Person() {
10     }; // 提供无参构造器
11     public Person(String name) { // 构造方法赋值
12         this.name = name;
13     }
14     public void show() { // 展示方法
15         System.out.println("我要去约会。。。");
16     }
17 }

Decorator

 1 package com.zqz.dp.decorator;
 2 /**
 3  * @author Qin
 4  * 装饰类,因为要对对象进行装饰,所以需要传递对象的引用,而且调用对象的具体方法
 5  */
 6 public abstract class Decorator extends Person {
 7     private Person per;        //person对象
 8     public Decorator(Person per) {        //构造方法表示对哪个对象进行装饰
 9         this.per = per;
10     }
11     @Override
12     public void show() {
13         if(per!=null){
14             per.show();
15         }
16     }
17 }

WearDecorator

 1 package com.zqz.dp.decorator;
 2 /**
 3  * @author Qin
 4  * 第一个装饰类,继承自装饰类。
 5  */
 6 public class WearDecorator extends Decorator {
 7     public WearDecorator(Person per) {    //指明被装饰的类
 8         super(per);    //调用父类的操作
 9     }
10     @Override
11     public void show() {    //覆写父类方法
12         this.ware();    //出门前进行操作
13         super.show();    //调用父类方法
14     }
15     public void ware(){        //出门前进行打扮操作
16         System.out.println("打扮中。。。。");
17     }
18 }

CallDecorator

 1 package com.zqz.dp.decorator;
 2 /**
 3  * @author Qin
 4  * 第一个装饰类,继承自装饰类。
 5  */
 6 public class CallDecorator extends Decorator {
 7     public CallDecorator(Person per) {    //指明被装饰的类
 8         super(per);    //调用父类的操作
 9     }
10     @Override
11     public void show() {    //覆写父类方法
12         super.show();    //调用父类方法
13         this.call();    //出门后添加逻辑
14     }
15     public void call(){        //出门口打电话
16         System.out.println("打电话改见面地点。。。");
17     }
18 }

Client

 1 package com.zqz.dp.decorator;
 2 /**
 3  * @author Qin
 4  * 场景类
 5  */
 6 public class Client {
 7     public static void main(String[] args) {
 8         Person per=new Person("张三");        //实例化person对象
 9         System.out.println("------第一种装扮-------");
10         Decorator  wear=new WearDecorator(per);    //用装饰类1对person对象进行装饰
11         Decorator  call=new CallDecorator(wear);    //用装饰类2对装饰类1对象进行装饰,递归
12         call.show();      //调用装饰类中的方法
13     }
14 }

  装饰模式的定义:动态的给一个对象添加一些额外的逻辑操作。

  装饰模式有如下四个角色:

  1、  Component抽象构件:相当于所有的person都应该有一个父类,这里因为只有张三一个对象,所有被我省略了。该类一般为抽象类或接口。

  2、  ConcreteComponent:具体构件,相当于上面的person。

  3、  Decorator装饰角色:装饰对象的统一进口,一般为抽象类,但方法不一定为抽象方法。

  4、  ConcreteDecorator具体装饰角色:表示具体的装饰类,CallDecorator等。

装饰模式的优点:

  1、  装饰类与被装饰类可以独立发展,相互不耦合。

  2、  装饰对象可拓展实现类的功能。(目的)

装饰模式的缺点:

  如果存在多重装饰的话,就会变得非常复杂。一般尽量减少装饰的量。

装饰模式的使用场景:

  1、  需要对一个类的功能进行拓展。

  2、  需要动态的给一个对象添加功能,并动态的撤销。

  3、  需要对一批兄弟类进行添加功能。

装饰模式与代理模式的异同:

  其实装饰模式就是静态代理的一种体现,但不能把代理和装饰混为一谈。

  在装饰模式中,我们都需要显示的指明我们要进行装饰的对象,这和静态代理是很相似的,但是代理模式的功能是实现对对象访问的控制,而装饰模式主要是对实现类功能的添加。

  还有的是,代理类中注重的是对对象访问的控制,在client端,一般我们只需要知道代理类的存在即可,不需要知道实现类的存在,也就是说一般使用的是普通代理或者虚拟代理,代理中最重点的是动态代理,实际开发中很少使用静态代理。

  在jdk中,代理模式使用的特别多,如动态代理Proxy。而装饰模式使用的较少,向java.io包中使用的就是装饰模式。

InputStream in=new DataInputStream(new FileInputStream("text.txt"));

  举两个例子来说明分别使用代理和装饰的情况

  1、西游记中,孙悟空和唐僧路过高老庄时,悟空代替了高家三小姐去见八戒,这个时候八戒并不知道来的“高家三小姐”是悟空,而这个时候如果八戒只是对说说话,牵牵手,那么“高家三小姐”还是同意的,而如果八戒想亲她,那就不能让他得逞了。

  2、悟空学会了七十二变之后,如果他变成鱼,那么他就具有了游泳的能力;如果他变成了鸟,那他就具有了飞翔的能力;也就是说悟空变成了什么,就具有了什么的功能。但是不管悟空怎么变,他还是一只猴子,这是变不了的。

  相必大家应该都很清楚吧,第一个是代理,因为对对象的访问进行了控制;第二个是装饰,因为为对象添加了功能,进行了扩展

原文地址:https://www.cnblogs.com/littleQin/p/3689114.html