装饰者模式适用于一个类,可以用很多种属性修饰。

比如有一个煎饼5元,可以加很多东西,比如,加鸡蛋1元,加香肠2元等等。

如果使用继承,就会有很多类需要创建,需要创建加1个鸡蛋的煎饼,2个鸡蛋的煎饼,或者加1个香肠2个鸡蛋的煎饼,等等等等类。

如果给煎饼类直接加鸡蛋数量,香肠数量等属性,那么当又有新的附加品,比如辣条的时候,就需要修改此煎饼类,鉴于开闭原则,我们使用装饰者模式。

首先我们创建一个抽象的煎饼类和一个抽象的附加品类,且附加品继承自煎饼类。

package decorate;

/**
 * 煎饼抽象类
 */
abstract class Pancake {
    //获得煎饼的描述
    abstract String getDesc();

    //获得煎饼的价格
    abstract int cost();
}

package decorate;

/**
 * 附加物的抽象类,比如鸡蛋,火腿,香菜等
 */
abstract class Annexation extends Pancake {
}

此时,再创建一个真实的煎饼类,继承自抽象煎饼类,5块一个煎饼~

/**
 * 一个真实的煎饼类
 */
public class SinglePancake extends Pancake {

    @Override
    public String getDesc() {
        return "煎饼";
    }

    @Override
    public int cost() {
        return 5;
    }
}

再创建两个附加品类:加鸡蛋和加香肠的类,继承自抽象附加品类

/**
 * 加鸡蛋 假如加一个鸡蛋1块
 */
public class EggPancake extends Annexation {
    //被装饰的煎饼
    private Pancake pancake;

    public EggPancake(Pancake pancake){
        this.pancake = pancake;
    }

    public String getDesc() {
        return pancake.getDesc() + "+鸡蛋";
    }

    public int cost() {
        return pancake.cost() + 1;
    }
}

/**
 * 加香肠 假如香肠2块
 */
public class SausagePancake extends Annexation {
    //被装饰的煎饼
    private Pancake pancake;

    public SausagePancake(Pancake pancake) {
        this.pancake = pancake;
    }

    public String getDesc() {
        return pancake.getDesc() + "+香肠";
    }

    public int cost() {
        return pancake.cost() + 2;
    }
}

测试类

public class Demo {
    public static void main(String[] args) {
        //老板 我要一个煎饼 啥都不加
        Pancake singlePancake = new SinglePancake();
        System.out.println(singlePancake.getDesc() + ":" + singlePancake.cost() + "元");

        //老板 我要一个加两个鸡蛋的煎饼
        Pancake twoEggsPancake = new SinglePancake();
        //加两个煎饼
        twoEggsPancake = new EggPancake(twoEggsPancake);
        twoEggsPancake = new EggPancake(twoEggsPancake);
        System.out.println(twoEggsPancake.getDesc() + ":" + twoEggsPancake.cost() + "元");

        //老板 我要加一个鸡蛋,加一个香肠的煎饼
        Pancake eggAndSausagePancake = new SinglePancake();
        eggAndSausagePancake = new EggPancake(twoEggsPancake);
        eggAndSausagePancake = new SausagePancake(twoEggsPancake);
        System.out.println(eggAndSausagePancake.getDesc() + ":" + eggAndSausagePancake.cost() + "元");
    }
}

输出:

煎饼:5元

煎饼+鸡蛋+鸡蛋:7元

煎饼+鸡蛋+鸡蛋+香肠:9元

如果,此时增加了新的口味:辣条,就可以如同鸡蛋和香肠一样,增加辣条装饰类。