3.装饰者模式
1.装饰者模式是什么
装饰者模式定义比较抽象,我们可以举一个经典的例子来说明。奶茶店里有x种奶茶和y种配料。每一个产品用一种x和y中的1个或多个配料组成。请问怎么实现上述的功能?
方案一:x中的奶茶和y种配料,把所有搭配情况枚举出来,为每一个搭配方案定义一个类 ,显然,这种方式稍加改动就会让类暴炸,不妥。
方案二:超类drink中把所有的种类调料都内置到超类中。把y个配料,内置进去,但他们都是布尔类型的,在下面定义的方法用于判断,是否扩展类中是否有他们,或者是要加什么配料,同时是否要加钱。但这个方案有缺点,比如增删配料种类,如果要引入一个配料,就要改动这个超类。也就是新功能的引入,会影响原有功能,原有代码。这样就会在改动原有功能时,所有的引入都会产生bug,都有可能引入bug。
方案三:我们可以设计为装饰者模式—给一个对象动态地、透明地添加职能。比如2份巧克力+一份牛奶这种搭配。先new一个单品对象,然后包装到Milk,再然后包装到Chocolate,在包装在Chocolate里面,具体的费用计算是通过,代用最外层cost方法去获取,他会自己去获取自己里面包装的费用,然后一级级递归,去调用所有费用,从而获取所有费用;
通过这种方式结构,你会发现当调料很多的情况下,任意他随意组合,我们都可以通过这种递归的方式获取所有的费用。不像第一种方式一样,每新一个组合就要扩展一个类,导致类爆炸。而且你引入一个调料的时候,只需要在上面说的具体的调料上去扩展一个出来就行了,引入新调料的时候,不会对原有的功能造成任何影响。它引入自己引入自己,不会对原有代码造成影响。
2.类图
3.案例代码实现
抽象类Drink-----Component
public abstract class Drink {
private String describle="";
private double price=0;
public String getDescrible() {
return describle;
}
public void setDescrible(String describle) {
this.describle = describle;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public abstract double cost();
}
牛奶类和咖啡类-------ConcreteComponent
public class Milk extends Drink {
public Milk() {
super.setDescrible("10元牛奶");
super.setPrice(10);
}
@Override
public double cost() {
return super.getPrice();
}
}
public class Coffee extends Drink {
public Coffee() {
super.setDescrible("8元咖啡");
super.setPrice(8);
}
@Override
public double cost() {
return super.getPrice();
}
}
Decorator类
public class Decorator extends Drink {
private Drink Obj;//注意这里面有个父类的对象,因为这是个装饰者
public Decorator(Drink Obj){//所以实现这个装饰者时必须带入这个Drink对象放进去
this.Obj=Obj;
};
@Override
public double cost(){
return super.getPrice()+Obj.cost();
}
@Override
public String getDescrible()
{
return super.getDescrible()+"-"+super.getPrice()+"&&"+Obj.getDescrible();
}
}
Pearl类和Jelly类—ConcreteDecorator
public class Pearl extends Decorator {
public Pearl(Drink Obj) {
super(Obj);
super.setDescrible("3元珍珠");
super.setPrice(3);
}
}
*/
public class Jelly extends Decorator {
public Jelly(Drink Obj) {
super(Obj);
super.setDescrible("2元果冻");
super.setPrice(2);
}
}
测试:
public class Test {
public static void main(String[] args) {
//订单:2元果冻+3元珍珠+10元牛奶 测试
Drink d1=new Jelly(new Pearl(new Milk()));
System.out.println(d1.cost());
System.out.println(d1.getDescrible());
}
}