设计模式之装饰者模式

装饰者模式介绍:动态的将新功能附加到对象上。在对象的功能拓展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(opc原则)。

 装饰者模式类似于打包一个快递。

主体(Component):陶瓷、衣服。

包装(Decorator):报纸填充、塑料泡沫、纸板、木板。

 这边的Component主体一般是抽象的,因为具体的主体肯定是不少的,所以编码中一般是抽象类,具体子类ConcreteComponent继承这个抽象类(如果具体主体的分类超级多,中间可以再加层抽象类作为缓冲层,提取相同的部分)。Decorator也是需要继承主体类并聚合一个主体类。

以上说法十分抽象,例如有个例子:

1、咖啡店有很多咖啡总类,Espresso, ShortBlack,LongBlack, Decaf。

2、调料,milk(牛奶), soy(豆浆), chocolate(巧克力)

假如我点了一份LongBlack,点了两个巧克力和牛奶作为调料。现在需要用装饰者模式实现订单的组合以计算费用。我们便以上面描述的装饰者模式的思路来用代码实现。

Drink.java

public abstract class Drink {
    //描述
    public String des;
    //价格
    private float price = 0.0f;

    public String getDes() {
        return des;
    }

    public void setDes(String des) {
        this.des = des;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    //计算费用的方法
    public abstract float cost();
}

Coffee.java

public abstract class Coffee extends Drink {
    @Override
    public float cost() {
        return super.getPrice();
    }
}

这边的coffee就相当于上面说的缓冲层,因为,drink还分很多种,有果汁、茶、咖啡。 

LongBlack.java(这个是具体的咖啡)

public class LongBlack extends Coffee{
    public LongBlack(){
        setDes("LongBlack");
        setPrice(5.0f);
    }
}

Decorator.java

public class Decorator extends Drink {
    private Drink obj;

    public Decorator(Drink obj) {
        this.obj = obj;
    }

    @Override
    public float cost() {
        //先拿到自己的价格
        return super.getPrice() + obj.cost();
    }

    @Override
    public String getDes() {
        //返回自己的信息加被装饰者的信息
        return super.getDes() + " " + super.getPrice() + " && " + obj.getDes();
    }
}

Chocolate.java

public class Chocolate extends Decorator {

    public Chocolate(Drink obj) {
        super(obj);
        setDes("巧克力");
        setPrice(3.0f);
    }
    
}

Milk.java

public class Milk extends Decorator {
    public Milk(Drink obj) {
        super(obj);
        setDes("牛奶");
        setPrice(2.0f);
    }
}

Client.java

public class Client {
    public static void main(String[] args) {
        //1、先点一份LongBlack
        Drink order = new LongBlack();
        System.out.println("费用1=" + order.cost());
        System.out.println("描述=" + order.getDes());

        //2、加入一份牛奶
        order = new Milk(order);
        System.out.println("order 加入一份牛奶后 费用=" + order.cost());
        System.out.println("描述=" + order.getDes());

        //3、加入一份巧克力
        order = new Chocolate(order);
        System.out.println("order 加入一份巧克力后 费用=" + order.cost());
        System.out.println("描述=" + order.getDes());

        //4、加入一份巧克力
        order = new Chocolate(order);
        System.out.println("order 加入一份巧克力后 费用=" + order.cost());
        System.out.println("描述=" + order.getDes());
    }
}

输出的结果:

费用1=5.0
描述=LongBlack
order 加入一份牛奶后 费用=7.0
描述=牛奶 2.0 && LongBlack
order 加入一份巧克力后 费用=10.0
描述=巧克力 3.0 && 牛奶 2.0 && LongBlack
order 加入一份巧克力后 费用=13.0
描述=巧克力 3.0 && 巧克力 3.0 && 牛奶 2.0 && LongBlack

在代码可以看出来,以上LongBlack(主体)中的getDes()和cost()是直接返回,Decorator实例中的getDes()和cost()主要是递归的形式,遇到具体的主体,递归停止。

原文地址:https://www.cnblogs.com/chenmz1995/p/12441581.html