装饰者模式(Decorator)

1.装饰者模式:

    就是用来装饰别的类的,可以理解成 加油添醋(或锦上添花····)

    就像人一样,人就是原来的类,每一个装饰类就如一件件的衣服,可以根据需求随意组合的穿到人的身上。

    例子:

          面条,可以是牛肉面瘦肉面、·····等等,

          转换成java代码就是:

              面条 --- 抽象类 Noodle;

             牛肉面 ----  BeefNoodles;

             瘦肉面  ---- MeatNoodles;    

     ```````````这样就会有各种各样的面条的具体类了,

     关键不是数量的问题,假如有一个 加鸡蛋的牛肉面呢? 再新建一个 BeefAndEggNoodles?    

     那么,如果顾客的要求更多一点呢 加蛋加香肠的牛肉面呢·······················    

  

     应该怎么办呢,其实我们应该分清楚主次,很明显这里主体是牛肉面/瘦肉面,装饰的是配料(什么鸡蛋,香肠,香菜等·····),

     而且这些配料还有可能随意组合的,所以按配料来定义一个面条对象是不理智的。

    首先,先创建一个Noodle抽象类,这个没问题吧:

 1 package design.patterns.decorator;
 2 
 3 public abstract class Noodle {
 4    //描述,说明这是什么面
 5    public String description;
 6    
 7    public String getDescription(){
 8        return description;
 9    }
10    
11    //吃后感
12    public abstract String feeling();
13 }
View Code

   然后创建一个继承了Noodle类的 牛肉面类BeefNoodle

(可能有人会问,为什么鸡蛋,香肠这些才是配料,而牛肉不也是加在面里面的吗,牛肉应该也算是配料的一种啊;这里只是相对而言,因为相对于一个香肠,那些牛肉就已经不算是配料了,

 又例如蛋糕,巧克力蛋糕、冰激凌蛋糕、还有花瓣以及卡片,相对而言,花瓣和卡片才算是装饰,巧克力和冰激凌则应该认为是蛋糕的一部分了,当然这个标准你可以自己拿捏)

 1 package design.patterns.decorator;
 2 
 3 public class BeefNoodle extends Noodle{
 4     public BeefNoodle(){
 5         this.description = "这是一碗牛肉面";    
 6     }
 7     
 8     @Override
 9     public String feeling() {
10         return "牛肉面就是香。";
11     }
12 
13 }
View Code

 在还没有加其他配料前就先直接测试一下吧:TestNoodle

1 package design.patterns.decorator;
2 
3 public class TestNoodle {
4     public static void main(String[] args){
5         //这是普通的牛肉面。
6         Noodle noodle = new BeefNoodle();
7         System.out.println(noodle.feeling());
8     }
9 }
View Code

  结果如下:

           

 

   重点来了,关键来了,定义一个面条配料类NoodleDecorator

(因为这只是配料,可以理解为"加了·····配料的·····面",如:"加了 蛋 的 牛肉面",但这种面并不是真实存在的(不像牛肉面那么具体),所以声明为抽象类)

 1 package design.patterns.decorator;
 2 
 3 public abstract class NoodleDecorator extends Noodle{
 4     //同时它也是继承了Noodle,跟各种面是同一父类的,所以在多态上会更便利
 5     //这一步是关键,使用了组合,把"被装饰者"传进来让"装饰者"进行"装饰(包装,所谓的加油添醋)"
 6     public Noodle noodle;
 7     
 8     public NoodleDecorator(Noodle n){
 9         noodle = n;
10     }
11     @Override
12     public abstract String feeling() ;
13 }
View Code

 然后创建具体的装饰类,加蛋的配料面条类 AddEgg:

 1 package design.patterns.decorator;
 2 
 3 public class AddEgg extends NoodleDecorator{
 4 
 5     public AddEgg(Noodle n) {
 6         super(n);
 7     }
 8     
 9     @Override
10     public String feeling() {
11         return this.noodle.getDescription() +" +加了蛋才是最美味。";
12     }
13 
14 }
View Code

 再创建一个 加了香肠的类 AddSuasage

 1 package design.patterns.decorator;
 2 
 3 public class AddSausage extends NoodleDecorator{
 4 
 5     public AddSausage(Noodle n) {
 6         super(n);
 7     }
 8 
 9     @Override
10     public String feeling() {
11         return this.noodle.feeling() +" +加一根香肠后,更加回味无穷。";
12     }
13 
14 }
View Code

   好了,现在来开始装饰吧:

 1 package design.patterns.decorator;
 2 
 3 public class TestNoodle {
 4     public static void main(String[] args){
 5         //这是普通的牛肉面。
 6         Noodle noodle = new BeefNoodle();
 7         System.out.println(noodle.feeling());
 8         
 9         //老板,给我来晚加蛋的牛肉面
10         Noodle n1 = new AddEgg(new BeefNoodle());
11         System.out.println(n1.feeling());
12         
13         //老板,给我来晚加香肠的牛肉面
14         Noodle n2 = new AddSausage(new BeefNoodle());
15         System.out.println(n2.feeling());
16         
17         //加蛋 又加香肠的 牛肉面
18         Noodle n3 = new AddSausage(new AddEgg(new BeefNoodle()));
19         System.out.println(n3.feeling());
20     }
21 }
View Code

    如果这个测试类看着不爽,那就看这个吧:

 1 package design.patterns.decorator;
 2 
 3 public class TestNoodle {
 4     public static void main(String[] args){
 5         //这是普通的牛肉面。
 6         Noodle noodle = new BeefNoodle();
 7         System.out.println(noodle.feeling());
 8         
 9         //没蛋不好吃,在牛肉面的基础上加个蛋
10         noodle = new AddEgg(noodle);
11         System.out.println(noodle.feeling());
12         
13         //既然蛋都加了,再加跟香肠吧
14         noodle = new AddSausage(noodle);
15         System.out.println(noodle.feeling());
16     }
17 }
View Code

 

 结果如下图:

       

  

     总结一下:1. 什么时候用装饰者模式,当类的属性中存在很明显的主次关系,同时这些属性还有可能随意组合,就把那些作为装饰的属性以组合的方式动态添加到类中

                     2. 在Java的IO中,最常见的装饰者模式就是 BufferedInputStream bin = new BufferedInputStream(InputStream);

                        这里,buffer也是以组合的方式"装饰(添加到)"普通的inputStream中的

                    3. 缺点,所有的设计模式都共有的,类的数量增加了,每多一个装饰功能,就得新增一个装饰类;同时逻辑上复杂了不少,理解有一定难度。

posted @ 2015-02-09 18:39  一菲聪天  阅读(208)  评论(0编辑  收藏  举报