• 装饰者模式(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. 缺点,所有的设计模式都共有的,类的数量增加了,每多一个装饰功能,就得新增一个装饰类;同时逻辑上复杂了不少,理解有一定难度。

  • 相关阅读:
    猴子搬香蕉问题
    IE浏览器上传文件后返回结果会自动弹出下载框
    webstorm忽略node_modules目录
    webstorm中sass编译时目录或内容包含中文字符报错
    echarts实现自动轮播tooltip
    IIS处理并发请求时出现的问题及解决
    Zuul 2.1.5 设计分析
    基于 Canal 设计可扩展、高可用 binlog 同步集群
    k8s-coredns内部解析
    Istio使用Envoy转发Http请求错误码426 Upgrade Required
  • 原文地址:https://www.cnblogs.com/tommy-huang/p/4282186.html
Copyright © 2020-2023  润新知