意图

动态给对象添加一些额外的职责。

动机

  • 有时希望能给某个对象而不是整个类的所有对象添加一些功能。
  • 继承机制不够灵活,不能控制方法增强的时机(比如英雄李白拿蓝Buff,或者红Buff,Buff持续是有时间限制的)。
  • 一种较为灵活的方式是将对象(如李白)放入一个装饰对象(如Buff),由装饰对象在合适的时机对原对象(李白)的方法(如攻击力、冷却时间)进行增强

模式结构

装饰者模式结构.svg

效果

优点

  1. 比静态继承更灵活
    1. 可以运用添加分离的方法,在运行时增加和删除职责。
    2. 相比而言,继承机制要求每个添加的职责创建一个子类。
    3. 多个Decorator装饰的实例对象间可以混合匹配。
  2. 避免在层次结构高层的类有太多的特征
    1. 采用即用即付方式添加职责
    2. 最初的类的功能不会很复杂,而是逐渐给它添加功能,这样使得程序不会为了不必要的特征付出代价。
    3. 可以很容易定义新的Decorator类。

缺点

  1. Decorator与它的Component不一样
    1. Decorator是一个透明包装。从对象标识出发,被装饰的组件组件本身是有差别的。
    2. 因此,使用装饰时候,不应该依赖对象标识。
  2. 执行过程有许多小的对象产生
    1. 这些小对象差别主要是它们相互连接的方式上,而不是属性上。
    2. 对于不熟悉这种设计的人员,排错很困难。

实现

  1. 接口的一致性
    装饰对象Decorator的接口必须与它所装饰的组件Component接口是一致的。所以所有实际装饰对象ConcreteDecorator必须有一个公共父类Decorator(一般是作为抽象类)
  2. 省略抽象的Decorator类
    仅需要添加一个职责时候,抽象的Decorator类是不必要的,直接给出实际的装饰。
  3. 保持Component类的简单性
    Component接口重要作用是保证一致性,这个接口的简单性是很重要的(应该集中于定义方法,而不是存储数据,对数据表示的定义应该延迟到子类中)。否则Component类太复杂,难以大量使用,并且会导致子类无太多功能。
  4. 改变对象外壳与改变对象内核
    Decorator可以看作是对象的外壳,那么策略模式Strategy即可以视为对象的内核。
    Todo - 理解策略模式之后,进行比较归纳总结。

案例

1. 汽车功能定义

  1. public interface ICar {
  2. /**
  3. * 基本功能:移动
  4. */
  5. void move();
  6. }

2. 普通汽车实现

  1. public class Car implements ICar {
  2. /**
  3. * 实现基本功能:移动
  4. */
  5. @Override
  6. public void move() {
  7. System.out.println("陆地上跑");
  8. }
  9. }

3. 超级汽车抽象

  1. /**
  2. * 超级汽车 -> 增强的功能定义
  3. *
  4. * @author Jinhua
  5. */
  6. public abstract class SuperCar implements ICar {
  7. /**
  8. * 拿到有基本功能汽车的引用
  9. */
  10. private final ICar car;
  11. public SuperCar(ICar car) {
  12. this.car = car;
  13. }
  14. /**
  15. * 此处任然是移动功能,未进行方法增强
  16. */
  17. @Override
  18. public void move() {
  19. car.move();
  20. }
  21. }

4. 超级汽车实现

1) AI汽车

  1. public class AiCar extends SuperCar {
  2. /**
  3. * 继续拿到抽象类的基本功能汽车引用,构造其属性
  4. *
  5. * @param car 基本功能的汽车
  6. */
  7. public AiCar(ICar car) {
  8. super(car);
  9. }
  10. public void autoMove() {
  11. System.out.println("自动跑");
  12. }
  13. /**
  14. * 对移动方法进行了增强
  15. */
  16. @Override
  17. public void move() {
  18. super.move();
  19. autoMove();
  20. }
  21. }

2) 飞行汽车

  1. public class FlyCar extends SuperCar {
  2. public FlyCar(ICar car) {
  3. super(car);
  4. }
  5. public void fly() {
  6. System.out.println("天上飞");
  7. }
  8. @Override
  9. public void move() {
  10. super.move();
  11. fly();
  12. }
  13. }

3) 水中汽车

  1. public class WaterCar extends SuperCar {
  2. public WaterCar(ICar car) {
  3. super(car);
  4. }
  5. public void swim() {
  6. System.out.println("水里游");
  7. }
  8. @Override
  9. public void move() {
  10. super.move();
  11. swim();
  12. }
  13. }

测试主类

  1. public class Main {
  2. public static void main(String[] args) {
  3. System.out.println("基本功能");
  4. ICar iCar = new Car();
  5. iCar.move();
  6. System.out.println("---------------");
  7. System.out.println("增加新的功能:飞行");
  8. ICar flyCar = new FlyCar(iCar);
  9. flyCar.move();
  10. System.out.println("---------------");
  11. System.out.println("增加新的功能:水里游");
  12. ICar waterCar = new WaterCar(iCar);
  13. waterCar.move();
  14. System.out.println("---------------");
  15. System.out.println("增加两个新的功能,飞行,水里游");
  16. ICar waterCar2 = new WaterCar(new FlyCar(iCar));
  17. waterCar2.move();
  18. }
  19. }

运行结果

  1. 基本功能
  2. 陆地上跑
  3. ---------------
  4. 增加新的功能:飞行
  5. 陆地上跑
  6. 天上飞
  7. ---------------
  8. 增加新的功能:水里游
  9. 陆地上跑
  10. 水里游
  11. ---------------
  12. 增加两个新的功能,飞行,水里游
  13. 陆地上跑
  14. 天上飞
  15. 水里游