一、概念
装饰者模式是通过动态的将责任添加到对象身上。若要扩展能力,装饰者模式是比继承更具有弹性的替代方案。
个人理解:
《Head First 设计模式》书中有直接讲解,装饰者模式是通过对象实例进行增强,是运行时组装。继承是通过扩展新类实现增强,是编译时、是静态的。
故事说明(虚构),
广告公司准备 IPhone 7广告语,增强广告语 “IPhone 7是一款手机”。添加4G快速联网等标语。并且打印10w张。
继承方式工作:直接打印10w张“IPhone 7 是具有4G快速联网功能的手机。”广告语。交给 A粘贴去宣传。
装饰者模式工作:分别打印 “IPhone 7 是一款手机” ,“具有”,“4G快速联网”,“的功能”。等短语10w张。 让A 在粘贴的时,组装成“IPhone 7 是一款手机,具有4G快速联网等功能。” 的广告语宣传。
好了继承方式,装饰者模式都完成打印工作了。准备宣传的时候,甲方要求说,要添加“后置摄像1200万像素”的标语,让广告公司增加这个功能。
解决方案:
继承方式:重新打印10w张“IPhone 7 是具有后置摄像1200万像素、4G快速联网功能的手机。”
装饰者模式:打印10w张“后置摄像1200万像素、”短语,加上原来的短语,宣传拼接成广告语。
由例子可以看出。我们增强广告语时,继承方式,需要通过不断的重新对广告语编写实现增强。装饰者是通过不断的添加新的属性,灵活组装的完成广告语的增强。可见装饰者是更具有弹性的方式增强。
进一步假设,XXX手机也出了一部手机。也要4G快速联网、后置摄像1200万像素标语。是不是说,其实IPhone 7也应该是可通过组装的。
二、设计原则
开发-关闭原则,类应该对类扩展开放,对修改关闭。
找出应用中的变化之处,对立出来,拒绝和不变的代码混在一起。
三、代码实现
/**
* 此处实现装饰者模式,通过短语的方式装饰“IPhon7 是一台手机”.
* @author zhuang
*
*/
/**
* 广告标语
* @author zhuang
*
*/
public abstract class Slogan {
public abstract String toString();
}
/**
* IPhon 7 被修饰广告语
* @author zhuang
*
*/
public class IPhone7Slogan extends Slogan {
@Override
public String toString() {
return "IPhone7 是一款手机";
}
}
/**
* 短语条件装饰
* 设计原则 :变化之处,对立出来,拒绝和不变的代码混在一起。
* 统一实现toString, 变化的内容成为短语,交由子类诠释。
* @author zhuang
*
*/
abstract class PhraseDecorator extends Slogan {
/**
* 装饰对象
*/
protected Slogan slogan ;
public PhraseDecorator(Slogan slogan) {
this.slogan = slogan;
}
/**
* 统一实现
*/
@Override
public String toString() {
// TODO Auto-generated method stub
return slogan.toString() + getPhrase();
}
/**
* 这是变化,不同的短语是装饰过程中的变化之处
* @return
*/
public abstract String getPhrase();
}
/**
* 1200w后置摄像头
* @author zhuang
*
*/
public class RearCamera1200 extends PhraseDecorator{
public RearCamera1200(Slogan slogan) {
super(slogan);
}
@Override
public String getPhrase() {
// TODO Auto-generated method stub
return "1200w后置摄像头";
}
}
/**
* 4G联网
* @author zhuang
*
*/
public class Net4G extends PhraseDecorator {
public Net4G(Slogan slogan) {
super(slogan);
}
@Override
public String getPhrase() {
// TODO Auto-generated method stub
return "4G联网";
}
}
/**
* 辅助修饰
* @author zhuang
*
*/
public class AssistDecorator extends Slogan {
private String append ;
private Slogan slogan;
public AssistDecorator(Slogan slogan,String append) {
this.slogan = slogan;
this.append = append;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return append == null || append.length() ==0 ? slogan.toString()
: slogan.toString()+append;
}
}
// ---------------------------測試----------------------------------------
public class DecoratorPatternTest {
public static void main(String[] args) {
//最简单的广告语
Slogan slogan = new IPhone7Slogan();
System.out.println("最简单的广告语: "+slogan.toString()); //最简单的广告语
// 粗超增强版广告语
Slogan slogan2 = new IPhone7Slogan();
slogan2 = new Net4G(new RearCamera1200(slogan2));
System.out.println("粗糙版的广告语: "+slogan2.toString());
// 精细版增强广告语
Slogan slogan3 = new IPhone7Slogan();
slogan3 = new AssistDecorator(slogan3, "具有");
slogan3 = new AssistDecorator(new RearCamera1200(slogan3), "、");
slogan3 = new AssistDecorator(new Net4G(slogan3),"的功能");
System.out.println("增强的广告语: "+slogan3.toString()); //最简单的广告语
}
}
四、測試結果
五、总结
装饰者模式在功能增强的弹性上确实优于继承,动态组装,满足开发-关闭原则(很重要,很好保证程序的健壮性)。书中举例的JAVA IO 的类图,明明白白是使用装饰者模式进行IO操作增强。
ps:题外话,在消化这个模式的时候,我尝试用大白话告诉我女朋友。嗯,还挺好懂,消化知识的一种方式就是大白话和身边人姜明明白。可以继续尝试。