软件设计模式白话文系列(九)装饰者模式

时间:2022-11-14 22:07:09

1、描述

通过把对象引入包含行为的特殊封装中来为对象增强功能的模式。

2、模式结构与实现逻辑

  • 具体业务类:这个类的对象就是需要被装饰者模式加强的对象。需要实现抽象装饰类。
  • 抽象装饰类:装饰基类,用来记录装饰行为的抽象类或者接口。
  • 装饰类:抽象装饰类的实现类,引入抽象装饰类的对象,重写装饰行为,并在父类方法之前或之后进行而外的行为。

实现装饰者模式的大体思路就是:装饰类引用并实现(继承)业务类相同的接口(父类),再重写接口(父类)方法时,调用引用对象的方法,再添加自己逻辑。

3、实战代码

通过装饰者模式给一个战士增加战斗能力。战士类实现攻击接口,各种武器实现攻击接口,给战士装饰各种武器。

/**
 * 具体业务类
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-13 22:31:35
 */
public class Warrior implements Combat {

    @Override
    public void attack() {
        System.out.print("战士使用拳头攻击、");
    }
}

/**
 * 抽象装饰类
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-13 22:32:32
 */
public interface Combat {
    void attack();
}

/**
 * 装饰类
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-13 22:39:21
 */
public class Spear implements Combat {

    private Combat combat;

    public Spear(Combat combat) {
        this.combat = combat;
    }

    @Override
    public void attack() {
        combat.attack();
        System.out.print("长枪刺杀、");
    }
}

/**
 * 装饰类
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-13 22:42:28
 */
public class Sword implements Combat {

    private Combat combat;

    public Sword(Combat combat) {
        this.combat = combat;
    }

    @Override
    public void attack() {
        combat.attack();
        System.out.print("刀剑劈砍、");
    }
}

/**
 * 测试类
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-13 22:43:30
 */
public class Client {
    public static void main(String[] args) {
        Combat combat = new Warrior();
        combat.attack();
        System.out.println();

        Combat combat1 = new Spear(new Warrior());
        combat1.attack();
        System.out.println();

        Combat combat2 = new Sword(new Spear(new Warrior()));
        combat2.attack();
        System.out.println();

        Combat combat3 = new Spear(new Sword(new Warrior()));
        combat3.attack();
    }
}

执行结果:
软件设计模式白话文系列(九)装饰者模式

就这样我们无需修改代码,也无需新建子类就可以轻松扩展原对象的功能。这里需要注意的是:我们装饰的顺序会直接影响我们最终结果,例如例子中的 combat2 和 combat3 因为枪和剑的装饰顺序不一致导致攻击时顺序就发生了改变。

4、适用场景

  • 希望不修改代码的前提扩展业务行为。
  • 业务类无法继承时,例如被 final 关键字修饰的类,可以使用装饰者模式进行扩展

5、装饰者模式和代理模式比较

相同点:

两者同属结构性设计模式,两个模式都能基于组合原则再不修改原有类的前提下对当前行为进行扩展功能。

不同点:

装饰者是对行为未知扩展,而代理模式是对已有行为进行扩展。

装饰者的功能扩展和生命周期由客户端控制,代理模式的意图在于保护和隐藏原有对象,扩展和生命周期由代理控制,客户端只是无感调用。