装饰者模式

249 阅读3分钟

业务需求

咖啡馆多种咖啡,多种配料。需要单件咖啡加多种不同的配料,也可以单点咖啡。需要完成这个需求的设计,需要扩展性好可读性强。你会怎么设计呢?

解决方案

下面给出两种方案,凸显出装饰者模式的优缺点。

常规方案

给咖啡与配料各一个抽象类,咖啡与配料需继承各自抽象类,抽象类中有商品描述与价格。通过创建对象获取价格与描述,获取到该订单的价格与商品详情信息。从而实现了该需求。代码我就不贴出来了,大家可以想象,在很多很多配料与咖啡种类的情况下,计算一笔详情很麻烦,而且在扩展性上面显得很臃肿不堪。下面来看一下装饰者模式给出的解决方案。

装饰者模式

动态的将新功能附加到对象上,在对象功能扩展方面它比继承更有弹性,也体现出了开闭原则。先不着急看懂,我先简单的解释一下,心中有一个概念,在一对多的情况下先分清装饰者(多)与被装饰者(少),再给他们一个主体来简易开发,给咖啡与配料各自的缓冲类,详细的产品去实现详细的类即可。下面我们来看一下代码。

主体

public abstract class Drink {

    private 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();
}

缓冲层

// 被装饰者
public class Coffee extends Drink {

    @Override
    public float cost() {
        return super.getPrice();
    }
}
// 装饰者
public class Decorator extends Drink {
    // 通过构造器注入的方式引入被主体(装饰者)以方便获取咖啡信息
    private Drink obj;

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

    @Override
    public float cost() {
        // getPrice 是配料的价格
        return super.getPrice() + obj.cost();
    }

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

以下是产品的详细实现信息,只贴出部分详细可下载源码观看

public class Coffee1 extends Coffee {

    public Coffee1() {
        setDes("咖啡111");
        setPrice(1.0f);
    }
}
public class Dosing1 extends Decorator {

    public Dosing1(Drink obj) {
        super(obj);
        setDes("配料111");
        setPrice(1.0f);
    }
}

可以看出来装饰者引入了被装饰者,通过构造器注入获取到了装饰者信息,然后通过调用相应的get方法获取相关信息。下面我们测试一下:

public class CoffeeTest {

    public static void main(String[] args) {
        // 装饰者模式下单 一份咖啡 多种配料
        Drink drink = new Coffee1();
        System.out.println("收钱" + drink.cost());
        System.out.println("描述" + drink.getDes());

        // 加配料
        drink = new Dosing1(drink);
        System.out.println("加入配料收钱" + drink.cost());
        System.out.println("加入配料描述" + drink.getDes());
    }
}
收钱1.0
描述咖啡111
加入配料收钱2.0
加入配料描述配料111 1.0&&咖啡111

Process finished with exit code 0

小结

装饰者模式要分清主体,装饰者与被装饰者。装饰者通过引入被装饰者获取信息,从而操作获取到自己的需求信息即可。优点如下:动态的将新功能附加到对象上,在对象功能扩展方面它比继承更有弹性,常规的实现很容易造成类的数量众多,难以维护。

详细远源码地址: github.com/Liyinzuo/De…

以上便是我对装饰者模式的简介,如果那里错误或者不足的地方欢迎指正。