装饰模式的定义:
装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
场景:
星巴克去点咖啡,咖啡有意大利咖啡,美式咖啡,黑咖啡。添加佐料有豆浆,牛奶,巧克力。
客户的需求:一杯美式咖啡,外加一份牛奶,一份巧克力。需要多少钱?
对定义的解释:
动态地扩展一个对象的功能:可以动态的添加各种种类的咖啡。
包装对象,也就是装饰来包裹真实的对象:点了一杯美式咖啡,美式咖啡为具体被装饰者对象,佐料为抽象包装对象,豆浆,牛奶,巧克力,为具体包装对象。去添加进美式咖啡中,相当于利用牛奶,巧克力包装美式咖啡。
角色理解:
看不懂角色描述很正常,请根据下面代码来理解角色含义。
抽象组件角色:一个抽象接口,是被装饰类和装饰类的父接口。
抽象装饰角色:包含一个组件的引用,并定义了与抽象组件一致的接口。
具体被装饰者角色:意大利咖啡,美式咖啡,黑咖啡。这些单品咖啡就是 被装饰者 角色,共三个。
具体装饰角色:牛奶,巧克力,豆浆。这些佐料需要添加进咖啡内,所以理解为由它们包装单品咖啡。
代码:
抽象组件角色:编写一个抽象类,里面定义饮品的描述信息与价格,声明一个计算费用的抽象方法,不进行实现。由其子类去实现该抽象方法。
public abstract class Drink {
//对饮品的描述
public String des;
//饮品的价格
private float price = 0.0f;
//计算费用的抽象方法
public abstract float cost();
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;
}
}
缓存层:把单品咖啡的共同点抽取到Coffee类中,他们的共同的就是计算费用。第二个作用具有良好的扩展性,我们可以添加浓缩咖啡等其他种类的单品咖啡。
public class Coffee extends Drink {
//重写父类计算费用方法
@Override
public float cost() {
return super.getPrice();
}
}
具体被装饰者角色:类中设置了饮品的描述信息和价格。当客户点一杯美式咖啡,需要加俩份巧克力的时候。LongBlack 类为具体被装饰者角色,巧克力类为具体装饰者角色
public class Espresso extends Coffee {
public Espresso() {
setDes("意大利咖啡");
setPrice(6.0f);
}
}
public class LongBlack extends Coffee {
public LongBlack() {
setDes("美式咖啡");
setPrice(5.0f);
}
}
public class ShortBlack extends Coffee{
public ShortBlack() {
setDes("黑咖啡");
setPrice(4.0f);
}
}
抽象装饰角色: private Drink obj 组合被装饰者对象,cost()方法计算 具体被装饰者 被具体装饰者 包装后的总价格。
public class Decorator extends Drink {
//组合抽象类饮品,这里可以理解为拿到 被装饰者 对象
private Drink obj;
@Override
public float cost() {
//装饰者 包装 被装饰者 所需价格, obj.cost()获取被装饰者价格
//返回装饰者 包装 被装饰者 后的总价格
return super.getPrice()+obj.cost();
}
public Decorator(Drink obj) {
this.obj = obj;
}
@Override
public String getDes(){
//obj.getDes拿出 被装饰者信息
//super.des+" "+super.getPrice()拿出包装的信息
return super.des+" "+super.getPrice()+"&&"+obj.getDes();
}
}
具体装饰角色:这里写了三个类,牛奶,巧克力,豆浆。
public class Chocolate extends Decorator {
public Chocolate(Drink obj) {
super(obj);
setDes("巧克力");
//添加一份巧克力的价格
setPrice(3.0f);
}
}
public class Milk extends Decorator {
public Milk(Drink obj) {
super(obj);
setDes("牛奶");
//添加一份牛奶的价格
setPrice(2.0f);
}
}
public class soy extends Decorator {
public soy(Drink obj) {
super(obj);
setDes("豆浆");
//添加一份豆浆的价格
setPrice(1.0f);
}
}
客户端下单类:点了一份美式咖啡,一份牛奶,一份巧克力。
public class CofferBar {
public static void main(String[] args) {
//装饰者模式下的订单:2份巧克力+一份牛奶的LongBlack
//1.点一份LongBlack
Drink order = new LongBlack();
System.out.println("描述信息="+order.getDes());
System.out.println("价格="+order.cost());
//2.加一份牛奶
order = new Milk(order);
System.out.println("加入一份牛奶 描述信息="+order.getDes());
System.out.println("加入一份牛奶 价格="+order.cost());
//3.加一份巧克力
order = new Chocolate(order);
System.out.println("加一份巧克力 加入一份牛奶 描述信息="+order.getDes());
System.out.println("加一份巧克力 加入一份牛奶 价格="+order.cost());
}
}
结果示例: