2022年2月14日 作者 zeroheart

装饰器模式

动态的给已有对象添加一些功能,不改变原始结构,装饰器模式相比生成子类更为灵活。

缺点:多层装饰比较复杂。

我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。然后我们创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量。

RedShapeDecorator 是实现了 ShapeDecorator 的实体类。

DecoratorPatternDemo 类使用 RedShapeDecorator 来装饰 Shape 对象。
装饰器模式的 UML 图

上图,装饰器是一个实现被装饰的接口的抽象类,然后在添加两个实体类来具体实现不同形状的装饰功能。

参考 :装饰器模式 | 菜鸟教程 (runoob.com)

笔记中的形象例子:

1.装饰模式为已有类动态附加额外的功能就像LOL、王者荣耀等类Dota游戏中,英雄升级一样。每次英雄升级都会附加一个额外技能点学习技能。具体的英雄就是ConcreteComponent,技能栏就是装饰器Decorator,每个技能就是ConcreteDecorator;

英雄的技能,英雄的皮肤都可以使用装饰器模式

英雄是技能栏、皮肤栏是装饰器抽象类,具体的技能和皮肤就是装饰类

2. 在《绝地求生:刺激战场》游戏里面我们都知道。

  •  Kar 98K有5发子弹;
  •  装上弹匣后有10发子弹;
  •  装上4倍镜后可以进行4倍瞄准;
  •  装上8倍镜后可以进行4倍瞄准、8倍瞄准。

吃鸡游戏中,枪可以作为一个基础类,各种配件作为装饰器的抽象类,具体的4倍镜、8倍镜、弹夹等作为装饰类的具体实现。

public interface Gun {
    /** * 开火直至打空子弹 */
    public void fire();
}

public class Kar98K implements Gun {
    @Override
    public void fire() {
        System.out.println("砰*5");
    }
}
装饰上弹匣变更枪开火功能:

public abstract class AbstractMagazine implements Gun {
    private Gun gun;

    public AbstractMagazine(Gun gun) {
        this.gun = gun;
    }

    @Override
    public void fire() {
        gun.fire();
    }
}

public class Magazine extends AbstractMagazine {
    public Magazine(Gun gun) {
        super(gun);
    }

    @Override
    public void fire() {
        System.out.println("砰*10");
    }
}测试:
public class Demo {
    public static void main(String[] args) {
        System.out.println("[捡起一把98K]");
        Gun gun = new Kar98K();
        System.out.println("[开炮!]");
        gun.fire();
        System.out.println("[装饰上弹匣]");
        gun = new Magazine(gun);
        System.out.println("[开炮!]");
        gun.fire();
    }
}
输出:

[捡起一把98K]
[开炮!]
砰*5
[装饰上弹匣]
[开炮!]
砰*10
现在我要装上4倍镜,使它具有4倍瞄准功能,这是枪支原本没有的功能。

扩展枪支接口功能:

public interface Aim4X extends Gun {
    public void aim4X();
}

public abstract class AbstractTelescope4X implements Aim4X {
    private Gun gun;

    public AbstractTelescope4X(Gun gun) {
        this.gun = gun;
    }

    @Override
    public void fire() {
        gun.fire();
    }
}

public class Telescope4X extends AbstractTelescope4X {
    public Telescope4X(Gun gun) {
        super(gun);
    }

    @Override
    public void aim4X() {
        System.out.println("已进入4倍瞄准模式");
    }
}

/** * 55式4倍镜 */
public class Telescope4X55 extends AbstractTelescope4X {
    public Telescope4X55(Gun gun) {
        super(gun);
    }

    @Override
    public void aim4X() {
        System.out.println("4倍超级瞄准已部署");
    }
}
测试:

public class Demo {
    public static void main(String[] args) {
        System.out.println("[捡起一把98K]");
        Gun gun = new Kar98K();
        System.out.println("[装饰上4倍镜]");
        Aim4X aim4X = new Telescope4X(gun);
        System.out.println("[4倍瞄准]");
        aim4X.aim4X();
        System.out.println("[开炮!]");
        aim4X.fire();
        System.out.println("[先装饰上弹匣]");
        gun = new Magazine(gun);
        System.out.println("[再装饰上4倍镜]");
        aim4X = new Telescope4X(gun);
        System.out.println("[4倍瞄准]");
        aim4X.aim4X();
        System.out.println("[开炮!]");
        aim4X.fire();
        System.out.println("[人体描边?换上我的55式4倍镜]");
        aim4X = new Telescope4X55(gun);
        System.out.println("[4倍瞄准]");
        aim4X.aim4X();
        System.out.println("[开炮!]");
        aim4X.fire();
    }
}
输出:

[捡起一把98K]
[装饰上4倍镜]
[4倍瞄准]
已进入4倍瞄准模式
[开炮!]
砰*5
[先装饰上弹匣]
[再装饰上4倍镜]
[4倍瞄准]
已进入4倍瞄准模式
[开炮!]
砰*10
[人体描边?换上我的55式4倍镜]
[4倍瞄准]
4倍超级瞄准已部署
[开炮!]
砰*10
现在我要装上8倍镜,它具有4倍瞄准功能,也具有8倍瞄准功能。

扩展接口:

public interface Aim8X extends Aim4X {
    public void aim8X();
}

public abstract class AbstractTelescope8X implements Aim8X {
    private Gun gun;

    public AbstractTelescope8X(Gun gun) {
        this.gun = gun;
    }

    @Override
    public void fire() {
        gun.fire();
    }
}

public class Telescope8X extends AbstractTelescope8X {
    public Telescope8X(Gun gun) {
        super(gun);
    }

    @Override
    public void aim8X() {
        System.out.println("进入8倍瞄准模式");
    }

    @Override
    public void aim4X() {
        System.out.println("进入4倍瞄准模式");
    }
}
测试:

public class Demo {
    public static void main(String[] args) {
        System.out.println("[先装饰上弹匣]");
        gun = new Magazine(gun);
        System.out.println("[再装饰上8倍镜]");
        aim8X = new Telescope8X(gun);
        System.out.println("[8倍瞄准]");
        aim8X.aim8X();
        System.out.println("[敌人很近,换4倍]");
        aim8X.aim4X();
        System.out.println("[开炮!]");
        aim8X.fire();
    }
}
输出:

[先装饰上弹匣]
[再装饰上8倍镜]
[8倍瞄准]
进入8倍瞄准模式
[敌人很近,换4倍]进入4倍瞄准模式 [开炮!] 砰*10