大牧絮叨设计模式:装饰器模式

  • 2019 年 10 月 8 日
  • 笔记

1、 装饰器模式概述

装饰器模式(Decorator)[GOF95]是一种结构模式,通常情况下我们扩展一个类型的功能,优先选择的方案会是通过继承的方式进行功能扩展,但是Java单继承机制限制了这样的扩展本身就有很大局限性,在不影响原有类型继承模式的架构下,扩展类型的功能

由装饰器负责当前组件类型的功能拓展,更加符合面向对象的编程思想:你购买了一个房子,房子的装修就相当于装饰,就可以交给第三方的装修公司来进行完成了,装修公司在不改变你房子的本质的情况下根据你的需求装饰成需要的功能风格。

image.png

1) 核心组件

装饰器模式如下图所示,装饰器本身并没有改变Java语言的语法机制,只是将通过继承实现的功能拓展,通过聚合的方式转移到装饰类上了。

image.png

  • Component:核心组件,产品规范接口
  • ConcreteComponent:具体产品类型,创建该类型对象并执行对象的核心方法
  • Decorator:装饰器接口,内聚产品类型Component,达到包装目标对象的目的
  • ConcreteDecorator:具体装饰器,具体装饰器执行对应的方法,完成目标方法功能的扩展。

其实这里我们已经发现,即使没有核心组件Component,通过DecoratorConcreteComponent进行扩展也是可以的,他们之间通过聚合关系进行关联,完成对功能的拓展。但是通过继承/实现关系,可以规范对外暴露的接口调用一致,达到让客户调用的透明感知,这一点在下面的代码中就能体现出来。

2) 优点缺陷

优点

  • 装饰类和被装饰类解耦合,功能的扩展互相独立

缺陷

  • 多层功能叠加的装饰器会较为繁琐(复杂功能叠加通常会配合其他的设计模式实现

2、 Java实现

2.1、 产品规范接口House

package com.damu;    /**   * <p>项目文档: 装饰器模式 规范接口  </p>   *   * @author <a href="https://github.com/laomu/laomu.github.io">大牧</a>   * @version V1.0   */  public interface House {        /**       * 房子的功能方法       */      void business();  }

2.2、 具体产品ConcreteHouse

package com.damu;    /**   * <p>项目文档: 具体房子</p>   *   * @author <a href="https://github.com/laomu/laomu.github.io">大牧</a>   * @version V1.0   */  public class ConcreteHouse implements House {      @Override      public void business() {          System.out.println("大牧家的屋子..");      }  }

2.3、 装饰器规范Decorator

package com.damu;    /**   * <p>项目文档: 装饰器接口 </p>   *   * @author <a href="https://github.com/laomu/laomu.github.io">大牧</a>   * @version V1.0   */  public class Decorator implements House {        private House house;        public Decorator() {      }        public Decorator(House house) {          this.house = house;      }        @Override      public void business() {          house.business();      }  }

2.4、 具体装饰器类型

  • DecoratorWithHome
  • DecoratorWithBusiness
  • DecoratorWithSchool
package com.damu;    /**   * <p>项目文档: 家庭装饰</p>   *   * @author <a href="https://github.com/laomu/laomu.github.io">大牧</a>   * @version V1.0   */  public class DecoratorWithHome extends Decorator {        public DecoratorWithHome(House house) {          super(house);      }        @Override      public void business() {          System.out.println("居一隅而享万里");          super.business();          System.out.println("安得广厦千万间,大庇天下寒士俱欢颜");      }  }
package com.damu;    /**   * <p>项目文档: 商铺装饰器</p>   *   * @author <a href="https://github.com/laomu/laomu.github.io">大牧</a>   * @version V1.0   */  public class DecoratorWithBusiness extends Decorator {        public DecoratorWithBusiness(House house) {          super(house);      }        @Override      public void business() {          System.out.println("商铺装修");          super.business();          System.out.println("天对地,雨对风,大陆对长空,开业大吉,万事亨通");      }  }
package com.damu;    /**   * <p>项目文档: 教育装饰装修</p>   *   * @author <a href="https://github.com/laomu/laomu.github.io">大牧</a>   * @version V1.0   */  public class DecoratorWithSchool extends Decorator {        public DecoratorWithSchool(House house) {          super(house);      }        @Override      public void business() {          System.out.println("十年树木,百年树人");          super.business();          System.out.println("教育从娃娃抓起..");      }  }

2.5、 测试代码

package com.damu;    /**   * <p>项目文档: 项目测试类 </p>   *   * @author <a href="https://github.com/laomu/laomu.github.io">大牧</a>   * @version V1.0   */  public class DecoratorMain {        public static void main(String[] args) {            // 创建一个真实的房子          House house = new ConcreteHouse();            // 家 装修装饰--> 客户调用 House-> business()方法          House home = new DecoratorWithHome(house);          home.business();          System.out.println("--------------------");            // 商务 装修 装饰--> 客户调用 House-> business()方法          House business = new DecoratorWithBusiness(house);          business.business();          System.out.println("--------------------");            // 教育 装饰--> 客户调用 House-> business()方法          House school = new DecoratorWithSchool(house);          school.business();        }  }

3、 Python实现

Python本身的语法中是多继承机制的,所以前面对于Java语言语法的限制对于Python是没有意义的,在实现过程中完全可以通过继承的方式简单直接的完成功能拓展,而装饰器模式在Python中能让程序结构清晰,相比较继承实现,Python有语法的实现和自身装饰器的实现两种方式

3.1、 语法实现

"""  装饰器模式  """  import abc      class Component(metaclass=abc.ABCMeta):      """组件规范接口"""        def business(self):          raise NotImplemented("该方法必须实现...")      class ConcreteComponent(Component):        def business(self):          print("大牧家的小房子")      class Decorator(Component):      """装饰器"""      def __init__(self, component):          self.component = component        def business(self):          return self.component.business()      class DecoratorWithHome(Decorator):      """具体装饰器"""        def business(self):          print("功能添加:温馨的家")          super().business()          print("浊酒一杯家万里")      if __name__ == "__main__":      # 具体产品      component = ConcreteComponent()        # 装饰器对象      home = DecoratorWithHome(component)        # 暴露给用户的统一接口方法      home.business()

3.2、 装饰器实现

"""  装饰器模式  """  import abc      def decorator_with_home(fn):      """装饰器:可以被标记在函数/方法上,扩展方法功能"""      def wrapper(*args, **kwargs):          print("家书抵万金")          result = fn(*args, **kwargs)          print("万里江山如画..")          return result        return wrapper      class Component(metaclass=abc.ABCMeta):      """组件规范接口"""        def business(self):          raise NotImplemented("该方法必须实现...")      class ConcreteComponent(Component):      @decorator_with_home  # 装饰器注解扩展方法功能      def business(self):          print("大牧家的小房子")      if __name__ == "__main__":      # 具体产品      component = ConcreteComponent()        # 直接调用接口方法      component.business()

4、 Go实现

TODO