JAVA设计模式初探之装饰者模式

 java模式—装饰者模式

 

要点: 装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为


   实际上Java 的I/O API就是使用Decorator实现的。

 

装饰者模式

1、意图: 动态地给一个对象添加一些额外的职责。就增加功能来说, Decorator模式相比生成子类更为灵活。该模式以对客 户端透明的方式扩展对象的功能。

2、适用环境

(1)在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

(2)处理那些可以撤消的职责。

(3)当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的 子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

3、参与者

    1.Component(被装饰对象的基类)

      定义一个对象接口,可以给这些对象动态地添加职责。

    2.ConcreteComponent(具体被装饰对象)

      定义一个对象,可以给这个对象添加一些职责。

    3.Decorator(装饰者抽象类)

      维持一个指向Component实例的引用,并定义一个与Component接口一致的接口。

    4.ConcreteDecorator(具体装饰者)

      具体的装饰对象,给内部持有的具体被装饰对象,增加具体的职责。

4、类图

 

 

5、涉及角色

(1)抽象组件:定义一个抽象接口,来规范准备附加功能的类

(2)具体组件:将要被附加功能的类,实现抽象构件角色接口

(3)抽象装饰者:持有对具体构件角色的引用并定义与抽象构件角色一致的接口

(4)具体装饰:实现抽象装饰者角色,负责对具体构件添加额外功能。

  1 /定义被装饰者
  2 public interface Human {
  3     public void wearClothes();
  4 
  5     public void walkToWhere();
  6 }
  7 
  8 //定义装饰者
  9 public abstract class Decorator implements Human {
 10     private Human human;
 11 
 12     public Decorator(Human human) {
 13         this.human = human;
 14     }
 15 
 16     public void wearClothes() {
 17         human.wearClothes();
 18     }
 19 
 20     public void walkToWhere() {
 21         human.walkToWhere();
 22     }
 23 }
 24 
 25 //下面定义三种装饰,这是第一个,第二个第三个功能依次细化,即装饰者的功能越来越多
 26 public class Decorator_zero extends Decorator {
 27 
 28     public Decorator_zero(Human human) {
 29         super(human);
 30     }
 31 
 32     public void goHome() {
 33         System.out.println("进房子。。");
 34     }
 35 
 36     public void findMap() {
 37         System.out.println("书房找找Map。。");
 38     }
 39 
 40     @Override
 41     public void wearClothes() {
 42         // TODO Auto-generated method stub
 43         super.wearClothes();
 44         goHome();
 45     }
 46 
 47     @Override
 48     public void walkToWhere() {
 49         // TODO Auto-generated method stub
 50         super.walkToWhere();
 51         findMap();
 52     }
 53 }
 54 
 55 public class Decorator_first extends Decorator {
 56 
 57     public Decorator_first(Human human) {
 58         super(human);
 59     }
 60 
 61     public void goClothespress() {
 62         System.out.println("去衣柜找找看。。");
 63     }
 64 
 65     public void findPlaceOnMap() {
 66         System.out.println("在Map上找找。。");
 67     }
 68 
 69     @Override
 70     public void wearClothes() {
 71         // TODO Auto-generated method stub
 72         super.wearClothes();
 73         goClothespress();
 74     }
 75 
 76     @Override
 77     public void walkToWhere() {
 78         // TODO Auto-generated method stub
 79         super.walkToWhere();
 80         findPlaceOnMap();
 81     }
 82 }
 83 
 84 public class Decorator_two extends Decorator {
 85 
 86     public Decorator_two(Human human) {
 87         super(human);
 88     }
 89 
 90     public void findClothes() {
 91         System.out.println("找到一件D&G。。");
 92     }
 93 
 94     public void findTheTarget() {
 95         System.out.println("在Map上找到神秘花园和城堡。。");
 96     }
 97 
 98     @Override
 99     public void wearClothes() {
100         // TODO Auto-generated method stub
101         super.wearClothes();
102         findClothes();
103     }
104 
105     @Override
106     public void walkToWhere() {
107         // TODO Auto-generated method stub
108         super.walkToWhere();
109         findTheTarget();
110     }
111 }
112 
113 //定义被装饰者,被装饰者初始状态有些自己的装饰
114 public class Person implements Human {
115 
116     @Override
117     public void wearClothes() {
118         // TODO Auto-generated method stub
119         System.out.println("穿什么呢。。");
120     }
121 
122     @Override
123     public void walkToWhere() {
124         // TODO Auto-generated method stub
125         System.out.println("去哪里呢。。");
126     }
127 }
128 //测试类,看一下你就会发现,跟java的I/O操作有多么相似
129 public class Test {
130     public static void main(String[] args) {
131         Human person = new Person();
132         Decorator decorator = new Decorator_two(new Decorator_first(
133                 new Decorator_zero(person)));
134         decorator.wearClothes();
135         decorator.walkToWhere();
136     }
137 }

 

运行结果:

其实就是进房子找衣服,然后找地图这样一个过程,通过装饰者的三层装饰,把细节变得丰富。

关键点:
1、Decorator抽象类中,持有Human接口,方法全部委托给该接口调用,目的是交给该接口的实现类即子类进行调用。
2、Decorator抽象类的子类(具体装饰者),里面都有一个构造方法调用super(human),这一句就体现了抽象类依赖于子类实现即抽象依赖于实现的原则。因为构造里面参数都是Human接口,只要是该Human的实现类都可以传递进去,即表现出Decorator dt = new Decorator_second(new Decorator_first(new Decorator_zero(human)));这种结构的样子。所以当调用dt.wearClothes();dt.walkToWhere()的时候,又因为每个具体装饰者类中,都先调用super.wearClothes和super.walkToWhere()方法,而该super已经由构造传递并指向了具体的某一个装饰者类(这个可以根据需要调换顺序),那么调用的即为装饰类的方法,然后才调用自身的装饰方法,即表现出一种装饰、链式的类似于过滤的行为。
3、具体被装饰者类,可以定义初始的状态或者初始的自己的装饰,后面的装饰行为都在此基础上一步一步进行点缀、装饰。
4、装饰者模式的设计原则为:对扩展开放、对修改关闭,这句话体现在我如果想扩展被装饰者类的行为,无须修改装饰者抽象类,只需继承装饰者抽象类,实现额外的一些装饰或者叫行为即可对被装饰者进行包装。所以:扩展体现在继承、修改体现在子类中,而不是具体的抽象类,这充分体现了依赖倒置原则,这是自己理解的装饰者模式。


说的不清楚,有些只可意会不可言传的感觉,多看几遍代码,然后自己敲出来运行一下,基本上就领悟了。


下面这个例子也有助于理解 装饰的流程和作用

现在需要一个汉堡,主体是鸡腿堡,可以选择添加生菜、酱、辣椒等等许多其他的配料,这种情况下就可以使用装饰者模式。


汉堡基类(被装饰者,相当于上面的Human)

package decorator;  
  
public abstract class Humburger {  
      
    protected  String name ;  
      
    public String getName(){  
        return name;  
    }  
      
    public abstract double getPrice();  
  
}  

鸡腿堡类(被装饰者的初始状态,有些自己的简单装饰,相当于上面的Person)

package decorator;  
  
public class ChickenBurger extends Humburger {  
      
    public ChickenBurger(){  
        name = "鸡腿堡";  
    }  
  
    @Override  
    public double getPrice() {  
        return 10;  
    }  
  
}  

配料的基类(装饰者,用来对汉堡进行多层装饰,每层装饰增加一些配料,相当于上面Decorator)

package decorator;  
  
public abstract class Condiment extends Humburger {  
      
    public abstract String getName();  
  
}  

 

生菜(装饰者的第一层,相当于上面的decorator_zero)

package decorator;  
  
public class Lettuce extends Condiment {  
      
    Humburger humburger;  
      
    public Lettuce(Humburger humburger){  
        this.humburger = humburger;  
    }  
  
    @Override  
    public String getName() {  
        return humburger.getName()+" 加生菜";  
    }  
  
    @Override  
    public double getPrice() {  
        return humburger.getPrice()+1.5;  
    }  
  
}  


辣椒(装饰者的第二层,相当于上面的decorator_first)

package decorator;  
  
public class Chilli extends Condiment {  
      
    Humburger humburger;  
      
    public Chilli(Humburger humburger){  
        this.humburger = humburger;  
          
    }  
  
    @Override  
    public String getName() {  
        return humburger.getName()+" 加辣椒";  
    }  
  
    @Override  
    public double getPrice() {  
        return humburger.getPrice();  //辣椒是免费的哦  
    }  
  
}  


测试类

package decorator;  
  
public class Test {  
  
    /** 
     * @param args 
     */  
    public static void main(String[] args) {  
        Humburger humburger = new ChickenBurger();  
        System.out.println(humburger.getName()+"  价钱:"+humburger.getPrice());  
        Lettuce lettuce = new Lettuce(humburger);  
        System.out.println(lettuce.getName()+"  价钱:"+lettuce.getPrice());  
        Chilli chilli = new Chilli(humburger);  
        System.out.println(chilli.getName()+"  价钱:"+chilli.getPrice());  
        Chilli chilli2 = new Chilli(lettuce);  
        System.out.println(chilli2.getName()+"  价钱:"+chilli2.getPrice());  
    }  
  
}  

输出

鸡腿堡  价钱:10.0  
鸡腿堡 加生菜  价钱:11.5  
鸡腿堡 加辣椒  价钱:10.0  
鸡腿堡 加生菜 加辣椒  价钱:11.5  


 

作者:jason0539

微博:http://weibo.com/2553717707

博客:http://blog.csdn.net/jason0539(转载地址)

posted @ 2017-07-28 17:30  华sam  阅读(170)  评论(0编辑  收藏  举报