设计模式系列6---分隔与包装的装饰模式

enter image description here

在说完门面,需要提到一个他的近亲,就是同属于结构模式的装饰(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();
}

是不是感觉挺好的?

定义

enter image description here
我们看下这个UML类图
Component 是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象,比
如上面的套娃Doll,记住在装饰模式中,必然有一个被提取出来最基本的接口抽象类,就是 Component

ConcreteComponent 这个是最基本的接口或抽象类的实现,你要装饰的就是他。
例如我们举得例子,我们把日本套娃JapanDoll赋值给doll,然后我们对他进行了装饰。

Doll doll = new JapanDoll();
doll = new DecoratorMiniDollKiller(doll);

Decorator 一般是一个抽象类,实现接口或者抽象方法,它里面可不一定有抽象的方法,在它的属性里必然有一个 private 变量指向 Component,而且有调用的情况,所以你看到Decorator上有一个箭头指向Component

ConcreteDecoratorAConcreteDecoratorB 是两个具体的装饰类,你要把你最基本的东西装饰成你需要的东西。

后记

这个例子好像看起来不是符合装饰的样子
例如应该是公关公司对某个凤姐进行包装,从笑点到成为部分人敬仰,拿了绿卡,做了天使投资人!
例如我们买了一份礼物,但我们不会直接送给别人,还是会装饰下,用彩纸包装,加彩带装饰下。
这样的案例听起来更符合装饰的名字啊。

但只要核心思想能够领会到也算挺好的,把关键的易变的部分提出来成一个单独的类。然后层层的打包,成为最终我们想要的。

嗯,感觉应该给每个模式配套个口诀才对。哈哈
这个装饰模式我们就配个: 割变化类,叠包成果。怎样?

热评文章