前情提要:
http://blog.csdn.net/baidu_30889437/article/details/50917814
JVM: 上次给我招的工人不错啊!
oo 程序员:..
JVM: 现在来我开的博物馆生意越来越好了, 原来舞台剧的方式已经不能满足顾客的需求了
oo 程序员:..
JVM: 我决定要换一种运营模式, 把每个演播厅都租出去, 让那些想表演节目的对象们来租演播厅和相关器械, 这样我就能坐地收钱了!
oo 程序员:..
JVM: 合伙干吧? 怎么样? 你三我七!
oo 程序员:..
JVM: 四六?
oo 程序员: 成交! 先说说需求
JVM: 首先有不同类型的演播厅和不同的装饰品 / 器械, 每种物品都要付一定的租金, 你要做的就是一件事, 把总租金 (演播厅 + 饰品 / 器械) 算出来
oo 程序员: 把价格表给我!
卡通演播厅(CartoonStudio) 100
小丑演播厅(JokerStudio) 150
超级演播厅(SuperStudio) 300
气球(Balloon) 10
灯光(Lamplight) 25
麦克风(Microphone) 20
最后还写下了这个:
- public abstract class Anything_ex()
- {
- String description=" ";
- public String getDescription()
- {
- return description;
- }
- public abstract int cost();
- }
仔细一想也对, 无论是演播厅还是装饰品, 都需要描述 (description) 和 cost(价格), 写一个共同的父类无可厚非
接着写下你设计的第一个类:
- class CartoonandBalloon extends Anything_ex
- {
- ....
- public int cost()
- {
- return 100+10;
- }
- } // 带气球的卡通演播厅
第二个:
- class CartoonandLamplight extends Anything_ex
- {
- ...
- public int cost()
- {
- return 100+25;
- }
- } // 带灯光的卡通演播厅
第三个:
没有第三个了! 这样写下去可是无穷无尽的! 没办法, 换个思路
在演播厅里, 无论什么装饰品都有可能出现, 可以把演播厅 + 饰品看成一个整体, 通过饰品相应的 has 和 set 来控制饰品, 这样的话, 设计出来的类如下:
- class CartoonStudio extends Anything_ex
- {
- private boolean Balloon=false;
- .... // 省略其他变量, 这里只以气球为例
- public boolean hasBalloon()
- {
- return Ballon;
- }
- public void setBallon()
- {
- Balloon=true;
- }
- .......// 省略其他 has/set 方法
- public int cost()
- {
- int cost=100; // 卡通演播厅的初始价格为 100
- if(hasBalloon)
- {
- cost+=10;
- }
- else if(hasXXX).....// 省略类推下来的代码
- return cost;
- }
- }
这个看起来好多了, 不用写大爆炸数量的类, 虽然类写起来又臭 (无数的 has/set) 又长(的确很长)
但是有没有更好的方案?
答案当然是有的, 不过我们必须先明确一下, 上述设计的缺点
1. 臭
2. 长
3. 当饰品的租金改变的时候, 必须修改所有演播厅的代码(cost 部分), 我们当然不想这样, 我们想尽可能的少修改代码(松耦合)
4. 没有面对超类 / 接口编程
5. 没有将变化的部分独立开
6. 组合可能是更好的解决方案
下面让我们看看装饰者模式是如何解决上面问题的
装饰者模式: 动态的将责任加到对象上, 若要扩展功能, 装饰者提供了比继承更有弹性的替代方案
首先, 我们先将演播厅和他的装饰者们分开, 让装饰者继承另一个类:
- public abstract class Decorater_ex extends Anyting_ex
- {
- public abstract String getDescription();
- }
让装饰者子类重新实现 getDescription()即可
现在我们的思路是: 用装饰者装饰演播厅, 例如, 一个带麦克风和气球的卡通演播厅, 就先让气球装饰卡通演播厅, 再让麦克风装饰带气球的卡通演播厅
先让我们分别实现这 3 个类:
卡通演播厅:
- class CortoonStudio extends Anything_ex
- {
- public CortoonStudio()
- {
- description="CortonStudio";
- }
- publuc int cost()
- {
- return 100;
- }
- }
麦克风:
- class Microphone extends Decorater_ex
- {
- private Anything_ex studio;
- public Microphone(Anything_ex studio )
- {
- this.studio=studio;
- }
- public String getDescription()
- {
- return studio.getDescription()+",Microphone";
- }
- public int cost()
- {
- return studio.cost()+20;
- }
- }
气球:
- class Balloon extends Decorater_ex
- {
- private Anything_ex studio;
- public Balloon(Anything_ex studio )
- {
- this.studio=studio;
- }
- public String getDescription()
- {
- return studio.getDescription()+",Balloon";
- }
- public int cost()
- {
- return studio.cost()+10 ;
- }
- }
代码:
- Anything_ex CortoonStudio =new CortoonStudio(); // 一个卡通演播厅对象
- CortoonStudio=new Microphone(CortoonStudio); // 拿麦克风装饰
- CortoonStudio=new Balloon(CortoonStudio); // 拿气球装饰
- System.out.println(CortoonStudio.getDescription()+"="+CortoonStudio.cost());
输出结果:
CortonStudio,Microphone,Balloon=130
结果是正确的
这样写很好的解决了上面的问题
1. 运用组合进行扩展, 使当价格改变的时候, 只需要修改本身的代码
2. 面对超类 / 接口编程, 使饰品增加种类的时候, 并不需要修改被装饰者的代码
3. 开放关闭原则 : 代码应该对扩展开放, 对修改关闭
缺陷:
1. 子类繁多, 影响理解代码(java I/O 就是装饰者模式哦)
2. 无法应用于需要具体类的场景
来源: http://www.codeceo.com/java-decorator-pattern.html