
在说完门面,需要提到一个他的近亲,就是同属于结构模式的装饰(Decorator)。
按照开头写故事思路,这故事真是憋了好久才想到套娃的案例。
应该很多人都有看过套娃吧?没看过的就看上面的图,挺好懂得,就是一个嵌套一个的,挺有意思的。
不断的拆开这些套娃,发现里面还有更小的套娃,在拆开发现还有更更小的套娃….
打开过程是挺惊喜的,不过装回去就麻烦了,呵呵。
代码模拟
好了,假设我们现在有一个套娃在手上,我们该怎么模拟这个打开的过程呢?
模拟为 先拆开大的,再拆开中的,再拆开小的。总共三层,四个娃。
现在我们抽象出这个基本的操作。
public abstract class Doll {
public abstract void openDoll();
}
好了,这样我们就有一个娃娃类,里面有一个操作,叫打开套娃。
public class RussianDoll extends Doll {
private void OpenBigDoll() {
System.out.print("打开了最大的套娃");
}
@Override
public void openDoll() {
OpenBigDoll();
OpenMediumDoll();
OpenMiniDoll();
}
private void OpenMediumDoll() {
System.out.print("打开了中号套娃");
}
private void OpenMiniDoll() {
System.out.print("打开了小号套娃");
}
}
好了,我们还设置了一个俄罗斯套娃类, 实现了我们的Doll类,同时里面有打开大,中,小的三个套娃的过程。
这样我们就可以静静的调用它啦像下面这样的:
public static void main(String[] args) {
Doll doll = new RussianDoll();
doll.openDoll();
}
嗯,很好,到这里我们就可以愉快的拆开我们的套娃了。
不过有一个小问题,好像不是每次这个套娃都是这样的,有可能有六层呢?四层的呢?这时候怎么办,难道我们要去修改我们的RussianDoll的openDoll方法?这个好像不好吧,毕竟我们是希望最好是对修改关闭的啊。那这样就用继承咯,分别写开六层,五层~~~~一层的。
嗯,听起来也很有道理,不过还有一种情况啊。
那个,我们的套娃里面到底套的大小是多大的娃我们不知道啊。
假设我们最多有七层的,那就是有八个娃,我们分别编号1~8。
那么我们七层的套娃理论上可能的组合出来的套娃模式还真不少啊。
例如:
8-1,最大的8号里面直接只有一个最小的1号娃。
8-2-1,最大的8号里面有个2号的,2号里面是1号娃。
。。。。
面对这种情况,我们好像是可以穷尽所有的可能,不过我想没有一个程序员打算把这些类都写出来吧。
那么到底该怎么办那?我们的装饰模式这时候站出来,告诉你这不是绝症,只需要服用下他给的一帖装饰药就好了。
下面我们看下他给出的良方
装饰药
面对这个时候,他提出下面的解法.
你有很多套娃嘛,7层是吧? 那我就用7个杀手分别去搞定。
首先我们先抽象出一个基本的装饰套娃杀手,就像下面这样。
public abstract class DecoratorDollKiller extends Doll {
private Doll doll;
public DecoratorDollKiller(Doll doll) {
this.doll = doll;
}
public void openDoll() {
doll.openDoll();
}
}
接着我们再来派出7号到1好的杀手。不过为了方便,不可能真的都写出来,只写三个:大,中,小号的,表达意思就好了 ^_^
现在我们先写装饰大号套娃杀手
public class DecoratorBigDollKiller extends DecoratorDollKiller {
public DecoratorBigDollKiller(Doll doll) {
super(doll);
}
public void openDoll() {
OpenBigDoll();
super.openDoll();
}
private void OpenBigDoll() {
System.out.print("打开了最大的套娃");
}
}
接着是我们的中号杀手
public class DecoratorMediumDollKiller extends DecoratorDollKiller {
public DecoratorMediumDollKiller(Doll doll) {
super(doll);
}
public void openDoll() {
OpenMediumDoll();
super.openDoll();
}
private void OpenMediumDoll() {
System.out.print("打开了中号的套娃");
}
}
基本和我们的大号类似的套路,最后的小号也是一样的
public class DecoratorMiniDollKiller extends DecoratorDollKiller {
public DecoratorMiniDollKiller(Doll doll) {
super(doll);
}
public void openDoll() {
OpenMiniDoll();
super.openDoll();
}
private void OpenMiniDoll() {
System.out.print("打开了小号的套娃");
}
}
好了,我们的三个杀手准备好了。
现在是时候派出去给我们解决难题去了,消灭套娃难题。
假设现在有一个日本套娃,他被设置成了大套中,中套小的模式,那么我们就这样调用
public static void main(String[] args) {
Doll doll = new JapanDoll();
doll = new DecoratorMiniDollKiller(doll);
doll = new DecoratorMediumDollKiller(doll);
doll = new DecoratorBigDollKiller(doll);
doll.openDoll();
}
注意顺序哦。
如果这个套娃是大套小,我们只需要这么写
public static void main(String[] args) {
Doll doll = new JapanDoll();
doll = new DecoratorMiniDollKiller(doll);
doll = new DecoratorBigDollKiller(doll);
doll.openDoll();
}
如果这个套娃是中套小,我们这么写
public static void main(String[] args) {
Doll doll = new JapanDoll();
doll = new DecoratorMiniDollKiller(doll);
doll = new DecoratorMediumDollKiller(doll);
doll.openDoll();
}
是不是感觉挺好的?
定义

我们看下这个UML类图Component 是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象,比
如上面的套娃Doll,记住在装饰模式中,必然有一个被提取出来最基本的接口或抽象类,就是 Component。
ConcreteComponent 这个是最基本的接口或抽象类的实现,你要装饰的就是他。
例如我们举得例子,我们把日本套娃JapanDoll赋值给doll,然后我们对他进行了装饰。
Doll doll = new JapanDoll();
doll = new DecoratorMiniDollKiller(doll);
Decorator 一般是一个抽象类,实现接口或者抽象方法,它里面可不一定有抽象的方法,在它的属性里必然有一个 private 变量指向 Component,而且有调用的情况,所以你看到Decorator上有一个箭头指向Component。
ConcreteDecoratorA 和 ConcreteDecoratorB 是两个具体的装饰类,你要把你最基本的东西装饰成你需要的东西。
后记
这个例子好像看起来不是符合装饰的样子
例如应该是公关公司对某个凤姐进行包装,从笑点到成为部分人敬仰,拿了绿卡,做了天使投资人!
例如我们买了一份礼物,但我们不会直接送给别人,还是会装饰下,用彩纸包装,加彩带装饰下。
这样的案例听起来更符合装饰的名字啊。
但只要核心思想能够领会到也算挺好的,把关键的易变的部分提出来成一个单独的类。然后层层的打包,成为最终我们想要的。
嗯,感觉应该给每个模式配套个口诀才对。哈哈
这个装饰模式我们就配个: 割变化类,叠包成果。怎样?