设计模式之禅【装饰者模式】

真刀实枪之装饰模式

  • 罪恶的成绩单--利用中庸之道来化解斥责
    • 同是天涯沦落人:曾经的你有没有考完试让父母在试卷上签字的...
  • 先将这件“为了我们好”的事用类图展示一下吧:
  • 代码

    • SchoolReport

      package com.peng.zsz;
      
      /**
       * @author kungfu~peng
       * @data 2017年11月22日
       * @description
       */
      public abstract class SchoolReport {
          // 成绩情况
          public abstract void report();
      
          // 家长签字
          public abstract void sign(String name);
      }
      
    • FourthGradeSchoolReport

      package com.peng.zsz;
      
      /**
       * @author kungfu~peng
       * @data 2017年11月22日
       * @description
       */
      public class FouthGradeSchoolReport extends SchoolReport {
          // 我的成绩单
          @Override
          public void report() {
              // 成绩单的格式
              System.out.println("尊敬的家长:");
              System.out.println("您孩子的期末成绩为:【语文:78】【数学:67】【英语:69】");
              System.out.println("家长签名:");
          }
      
          // 家长签名
          @Override
          public void sign(String name) {
              System.out.println("签名者:" + name);
          }
      
      }
      
    • 接下来把这个成绩单给老爸看吧,类图增加Father
    • Father

      package com.peng.zsz;
      
      /**
       * @author kungfu~peng
       * @data 2017年11月22日
       * @description
       */
      public class Father {
          public static void main(String[] args) {
              // 把成绩单拿过来
              SchoolReport sr = new FouthGradeSchoolReport();
              // 看成绩单
              sr.report();
              // 签名-----休想
          }
      }
      
  • 当然这不肯能在一个优秀设计者的童年出现,那么怎么办呢?

    • 增加点技术工作:把成绩单封装一下
      1. 汇报最高成绩(心里战术:当最高成绩为80,你考了即使67,都会很容易接受)
      2. 汇报排名情况(不写总共有多少学生,只写写自己排多少名,钻个比较空子)
    • 既然战术有了,先纸上谈个兵吧
    • 代码

      • SugarFouthGradeSchoolReport

        package com.peng.zsz;
        
        /**
         * @author kungfu~peng
         * @data 2017年11月22日
         * @description
         */
        public class SugarFouthGradeSchoolReport extends FouthGradeSchoolReport {
            // 定义美化方法--最高成绩
            private void reportHighScore() {
                System.out.println("这次班里的最高分:【语文:88】【数学:90】【英语:87】");
            }
        
            // 排名
            private void sort() {
                System.out.println("这次排名:38名!");
            }
        
            // 重写汇报方法
            @Override
            public void report() {
                this.reportHighScore();// 润色--在、前奏
                super.report();// 汇报真实情况
                this.sort();// 汇报排名
            }
        
        }
        
      • Father

        package com.peng.zsz;
        
        /**
         * @author kungfu~peng
         * @data 2017年11月22日
         * @description
         */
        public class Father {
            public static void main(String[] args) {
                // 把成绩单拿过来
                SchoolReport sr = new SugarFouthGradeSchoolReport();
                // 看成绩单
                sr.report();
                // 签名
                sr.sign("KungFu");
            }
        }
        
      • 执行效果
        这次班里的最高分:【语文:88】【数学:90】【英语:87】
        尊敬的家长:
        您孩子的期末成绩为:【语文:78】【数学:67】【英语:69】
        家长签名:
        这次排名:38名!
        签名者:KungFu
        
    • 这次是躲过去了,纸是包不住火的,哪天父亲问班里有多少名同学时,这就尴尬了,难道继续扩展?类爆炸...

      • 好办,定义一批专门负责装饰的类,类图如下

        • 代码

          • Decorator

            package com.peng.zsz;
            
            /**
             * @author kungfu~peng
             * @data 2017年11月22日
             * @description
             */
            public abstract class Decorator extends SchoolReport {
                // 成绩单
                private SchoolReport sr;
            
                // 构造函数--将成绩单传进来
            
                public Decorator(SchoolReport sr) {
                    super();
                    this.sr = sr;
                }
            
                // 成绩单还是要被看到的
                public void report() {
                    this.sr.report();
                }
                //看完要签名
                public void sign(String name){
                    this.sr.sign(name);
                }
            
            }
            
          • HighScoreDecorator

            package com.peng.zsz;
            
            /**
             * @author kungfu~peng
             * @data 2017年11月22日
             * @description
             */
            public class HighScoreDecorator extends Decorator {
            
                public HighScoreDecorator(SchoolReport sr) {
                    super(sr);
                }
            
                // 定义美化方法--最高成绩
                private void reportHighScore() {
                    System.out.println("这次班里的最高分:【语文:88】【数学:90】【英语:87】");
                }
            
                @Override
                public void report() {
                    this.reportHighScore();
                    super.report();
                }
            
            }
            
          • SortDecorator

            package com.peng.zsz;
            
            /**
             * @author kungfu~peng
             * @data 2017年11月22日
             * @description
             */
            public class SortDecorator extends Decorator {
            
                public SortDecorator(SchoolReport sr) {
                    super(sr);
                }
            
                // 排名
                private void sort() {
                    System.out.println("这次排名:38名!");
                }
            
                @Override
                public void report() {
                    this.sort();
                    super.report();
                }
            
            }
            
          • Father

            package com.peng.zsz;
            
            /**
             * @author kungfu~peng
             * @data 2017年11月22日
             * @description
             */
            public class Father {
                public static void main(String[] args) {
                    // 把成绩单拿过来
                    SchoolReport sr;
                    // 原装的成绩单
                    sr = new FouthGradeSchoolReport();
                    // 加了最高分的成绩单
                    sr = new HighScoreDecorator(sr);
                    // 加了排名
                    sr = new SortDecorator(sr);
                    // 汇报成绩
                    sr.report();
                    // 签名
                    sr.sign("KungFu");
                }
            }
            
          • 执行结果

            这次排名:38名!
            这次班里的最高分:【语文:88】【数学:90】【英语:87】
            尊敬的家长:
            您孩子的期末成绩为:【语文:78】【数学:67】【英语:69】
            家长签名:
            签名者:KungFu
            

装饰模式的定义

  • Decorator Pattern
  • Attach additional responsibilities to an object dynamically keeping the same interface.Decorator provide a flexible alternative to subclassing for extending functionality.(动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式相比生成子类更灵活)
  • 通用类图

    • 角色说明:
      1. Component抽象构件:是一个接口或抽象类,就是定义我们最核心的对象,也是最原始的对象
      2. ConcreteComponent具体构件:被装饰的对象
      3. Decorator装饰角色:重点--属性必须有被装饰者
      4. ConcreteDecorator具体装饰角色:具体装饰者
    • 代码

      • Component

        package zs2;
        
        /**
         * @author kungfu~peng
         * @data 2017年11月22日
         * @description
         */
        public abstract class Component {
            // 抽象方法
            public abstract void operate();
        }
        
      • ConcreteComponent

        package zs2;
        
        /**
         * @author kungfu~peng
         * @data 2017年11月22日
         * @description
         */
        public class ConcreteComponent extends Component {
            @Override
            public void operate() {
                System.out.println("do Something!");
            }
        
        }
        
      • Decorator

        package zs2;
        
        /**
         * @author kungfu~peng
         * @data 2017年11月22日
         * @description
         */
        public abstract class Decorator extends Component {
            private Component component = null;
        
            // 构造函数--传递对象
            public Decorator(Component component) {
                super();
                this.component = component;
            }
        
            // 委托给被修饰者执行
        
            @Override
            public void operate() {
                this.component.operate();
            }
        
        }
        
      • ConcreteDecorator1

        package zs2;
        
        /**
         * @author kungfu~peng
         * @data 2017年11月22日
         * @description
         */
        public class ConcreteDecorator1 extends Decorator {
            public ConcreteDecorator1(Component component) {
                super(component);
            }
        
            // 自定义修饰方法
            private void method1() {
                System.out.println("修饰1");
            }
        
            // 覆写方法
            @Override
            public void operate() {
                this.method1();
                super.operate();
            }
        
        }
        
      • ConcreteDecorator2

        package zs2;
        
        /**
         * @author kungfu~peng
         * @data 2017年11月22日
         * @description
         */
        public class ConcreteDecorator2 extends Decorator {
            public ConcreteDecorator2(Component component) {
                super(component);
            }
        
            // 自定义修饰方法
            private void method2() {
                System.out.println("修饰2");
            }
        
            // 覆写方法
            @Override
            public void operate() {
                this.method2();
                super.operate();
            }
        
        }
        
      • Client

        package zs2;
        
        /**
         * @author kungfu~peng
         * @data 2017年11月22日
         * @description
         */
        public class Client {
            public static void main(String[] args) {
                // 创建部件
                Component component = new ConcreteComponent();
                // 装饰1
                component = new ConcreteDecorator1(component);
                // 在装饰1的基础上再装饰2
                component = new ConcreteDecorator2(component);
                component.operate();
            }
        }
        
      • 执行结果

        修饰2
        修饰1
        do Something!
        

装饰模式的应用

  • 装饰模式的优点
    1. 装饰类和被装饰类可以独立发展,而不会互相耦合
    2. 装饰模式是继承关系的一个替换方案
    3. 装饰模式可以动态的扩展一个实现的功能
  • 装饰模式的缺点
    1. 多层的装饰是比较复杂的---尽量减少装饰类的数量,以便降低系统的复杂度
  • 装饰类的使用场景
    1. 需要扩展一个类的功能,或给一个类增加附加功能
    2. 需要动态的给一个对象增加功能,这些功能可以再动态的撤销
    3. 需要为一批的兄弟类进行改装或加装功能

最佳实践

  • 装饰模式是对继承的有力补充,增加了其灵活性,解决了类膨胀的问题
  • 装饰模式可以动态地增加功能
  • 装饰模式的扩展性非常好,对于业务的变更,通过装饰模式来重封装一个类,而不是通过继承来完成

声明

  • 摘自秦小波《设计模式之禅》第2版;
  • 仅供学习,严禁商业用途;
  • 代码手写,没有经编译器编译,有个别错误,自行根据上下文改正。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乘风御浪云帆之上

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值