装饰者模式:
动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
下面我们以星巴兹咖啡为例:
我们都知道星巴兹是以扩张速度最快而闻名的咖啡连锁店,如果你在街角看到它的店,在对面街上肯定还会看到另一家。
因为扩张速度实在太快了,他们准备更新订单系统,以合乎他们的饮料供应要求。
他们原先的类设计是这样的。。。。。
定义一个名为Beverage的抽象类,店内所提供的饮料都必须继承自此类。该类中定义了一个名为description(叙述)的实例变量,由每个子类设置,用来描述做饮料 ,例如“超忧深焙(Daik Roast)咖啡豆”。还有一个cost()方法是抽象的,子类必须定义。自己的实现,此是子类返回饮料的价钱,同时还有一个getDescription()方法返回此叙述。
购买咖啡时,也可以要求在其中加入各种调料例如:蒸奶,豆浆,魔卡或覆盖奶泡。星巴兹会根据所加入的调料收取不同的收费的费用。
但是由于有很多种饮料,你这所每种调味料都要继承Beverage类的话,那么就要“类爆炸”了。
这时,我们应该用到
装饰者模式。
设计原则:开放-关闭原则
开放-关闭原则:类应该对扩展开放,对修改关闭。
我们的目标是允许类容易扩展,在不修改现有代码的情况下,就可搭配新的行为。如能实现这样的目标,有什么好处呢?这样的设计具有弹性可以应对改变,可以接受新的功能来应对改变的需求。
下面我们来认识装饰者模式,以一杯咖啡为例,如果顾客想要一杯摩卡和奶泡深焙咖啡,那么,要做的是:
1.拿一个深焙咖啡(DarkRoast)对象
2.以摩卡(Mocha)对象装饰它
3.以奶泡(Whip)对象装饰它
4.调用cost()方法,并依赖委托(delegate)将调料的价钱加上去
前面我们说过的
DarkRoast对象继承Beverage,下面我们定义Beverage对象
public abstract class Beverage{
String description="Unknown Beverage";
public String getDescription(){
return description;
}
public abstract double cost();
}
下面我们看看DarkRoast对象
public class DarkRoast extends Beverage{
public DarkRoast(){
description="DarkRoast";
}
public double cost(){
return 1.99;
}
}
为了达到类的 匹配,我们的调料(Condiment)也应该继承Beverage
public abstract class Condiment extends Beverage{
public abstract String getDescription();//所有的 装饰者都必须重新实现
}
下面我们便可以定义摩卡(Mocha)和奶泡(Whip)对象来装饰深焙(DarkRoast)咖啡了
public class Mocha extends Condiment{
Beverage beverage;//用一个实际变量记录饮料,也即是被装饰者
public Mocha(Beverage beverage){
this.beverage=beverage;
}
public String getDescription(){
return beverage.getDescription+",Mocha";
//我们希望叙述不只是描述饮料("DarkRoast"),而是完整地连调料都描述出来("DarkRoast,Mocha")所以首先利用委托的做法,得到一个叙述,然后在其加上附加的叙述(例如 "Mocha")
}
public double cost(){
return 0.20+beverage.cost;//要计算带Mocha饮料的价钱。首先把调用委托给装饰对象,以计算价钱,然后加上Mocha的价钱,得到最好的结果。
}
}
奶泡(Whip)对象也同样的道理。
现在我们便可以享受装饰者模式带来的方便了。
public class StartbuzzCoffe{
public static void main(String[] args){
Beverage beverage=new DarkRoast();
System.out.println(beverage.getDescription()+" $"+beverage.cost());
beverage=new Mocha(beverage);
System.out.println(beverage.getDescription()+" $"+beverage.cost());
}
}
到现在,装饰者模式基本了解了,下面总结一下:
1.继承属于扩展形式之一,但不见得是达到弹性设计的最佳方式
2.在我们设计中,应该允许行为可以被扩展,而无须修改现有的代码
3.组合和委托可用于 在运动时动态地加上新的行为
4.除了继承,装饰者模式也可以让我们扩展行为
5.装饰者模式意味着一群装饰者类,这些类用来包装具体组件
6.装饰者类反映出被装饰的组件类型(事实上,他们具有相同的类型,都经过接口或继承实现)
7.装饰者可以在被装饰者的行为前面与/或后面加上自己的,甚至将被装饰者的行为整个取代掉,而达到特定的目的
8.你可以使用无数个装饰者包装一个组件
9.装饰者一般对组件的客户是透明的,除非客户程序依依赖于组件的具体类型
10.装饰者会导致设计中出现许多小的对象,如果过度使用,会让程序变得复杂