以下文章内容来源:微信公众号(Java知音)文章,设计模式是什么鬼(装饰)

装饰,在某物件基础上加以修饰,装点,使得原本的朴素变得华丽,达到化腐朽为神奇的效果。比如我们从开发商买来的毛坯房,必然要进行室内装潢这么一项工程,什么简约风啊,北欧风啊,地中海,美式中式等等,当然萝卜青菜各有所爱,每个人装出的房子都各有差异,但不管何种风格,这都是对原本毛坯房的装饰,留给业主按照自己的喜好进行二次加工,这也是为什么有时候毛坯二手房比装修过的要好卖,有成品就一定得有半成品,这样才能把更多的选择留给用户,使得装饰成为可能。

人靠衣装马靠鞍,当然不止是装修有这么神奇的效果,对于女生化妆来说我们也是深有体会,每当女友回家卸妆后素面朝天的时候我们的内心是崩溃的,有种当初相亲被骗的感觉。

显而易见,女友每天出门之前进行的那场洗礼是多么的神圣,多么的不可或缺。诚然,化妆的过程对于男人来说充满了神秘色彩,但对于女人来说更像是一场洗礼,怀揣着信仰与敬畏感进行的一场仪式,最终会像魔法一般把自己的脸变得完美无瑕,更有甚者浓妆艳抹地连毛孔都看不到。

作为研发人员,我们一定不能放过对于这项神秘工程的拆解分析,开始我们的工作。首先每个人要展示自己那必然有一个标准行为show(),我们将它抽象出来作为接口Showable。

1
2
3
public interface Showable {
public void show();//定义展示行为
}

当然,女友会这门功夫了,所以实现了此行为并施展其“美丽的脸庞”了,但此时只是原生态的素颜。

1
2
3
4
5
6
7
8
public class Girl implements Showable{

@Override
public void show() {
System.out.print("女孩的素颜");
}

}

没什么复杂的,直接调用的话会是素面朝天直面惨淡的人生,这样当然达不到美颜效果了,何以登上人生巅峰。那么接下来要进行化妆了,这里必须依靠一种神秘而又昂贵的东西,化妆品登场了,它同样实现了Showable接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Decorator implements Showable{//化妆品粉饰器

Showable showable;//持有某个善于展示的家伙

public Decorator(Showable showable) {//构造时注入这个家伙
this.showable = showable;
}

@Override
public void show() {
System.out.print("粉饰(");//化妆品粉饰
showable.show();//这家伙素面朝天的秀
System.out.print(")");//粉饰打完收工
}

}

我们可以发现,在构造化妆品类的时候可以把女孩给注入进来,目的在于调用女孩的show方法,但对于其原本的具体行为装饰器一无所知,并且没有加入任何逻辑限制,它所做的无非是“画龙点睛”,“锦上添花”。接下来我们来运行一下看结果。

1
2
3
4
5
6
7
public class Client {
public static void main(String[] args) {
//用装饰器包裹女孩show出来
new Decorator(new Girl()).show();
//结果:粉饰(女孩的素颜)
}
}

我们可以看到,只需要新建装饰器的时候把女孩给包装进去就得到了粉饰过的美颜,是不是非常简单?然而此时有女朋友会嫌弃了,“只是打粉底这么简单吗?眼霜呢?口红呢……”。

好吧,为了满足女友的要求,我们得再多一些设计。想想看这些化妆品,不管是什么都有共同的特性,也就是说他们统统都可以装饰原生态的素颜展示方法show,那我们何不把这些特性抽象出来呢?开始行动,修改我们的装饰类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public abstract class Decorator implements Showable{

protected Showable showable;

public Decorator(Showable showable) {
this.showable = showable;
}

@Override
public void show() {
showable.show();//直接调用不做加任何粉饰。
}

}

我们把化妆品类给改成抽象类,重写show方法,但不做任何粉饰了,这里我们留给子类具体的某个化妆品去做装饰吧。化妆首先第一步一定要打底了,这里我们首先加入一个粉底类。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class FoundationMakeup extends Decorator{

public FoundationMakeup(Showable showable) {
super(showable);//调用化妆品父类注入
}

@Override
public void show() {
System.out.print("打粉底(");
showable.show();
System.out.print(")");
}
}

我们可以看到粉底类继承了化妆品类,当然这个粉底的show方法一定要加以修饰了,在原生态的前后都进行了打粉底操作。同样地,打完粉底后再画个口红吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Lipstick extends Decorator{

public Lipstick(Showable showable) {
super(showable);
}

@Override
public void show() {
System.out.print("涂口红(");
showable.show();
System.out.print(")");
}
}

最后,我们把女友、粉底、口红层层包裹起来并运行,结果如愿以偿。

1
2
3
4
5
6
7
8
public class Client {
public static void main(String[] args) {
//口红包裹粉底,再包裹女友。
Showable madeupGirl = new Lipstick(new FoundationMakeup(new Girl()));
madeupGirl.show();
//运行结果:涂口红(打粉底(女孩的脸庞))
}
}

如果女友对这种淡妆效果还是不满意,我们可以继续添加化妆品类,睫毛膏、眼线、眉笔、腮红等等等等,只需要层层包裹起来,最终实现女友浓妆艳抹的梦想。

我们观察这种装饰器模式结构,是不是似曾相识呢?没错,其实装饰器模式在JDK里就有很多应用,比如Java IO包里的众多流处理类。

1
new BufferedReader(new InputStreamReader(new FileInputStream(filePath)));

当然,流处理类当然要比我们的例子复杂的多,但其基本思想和我们去繁就简的例子异途同归,这些对象就好像是俄罗斯套娃一样层层包裹,层层装饰,每套一层就会多出一些功能出来,我们更可以自由搭配,实现不同的组合功能。

所以,不管是女生化妆还是程序员写代码,我们都不可能弄出一个巨大的类然后去搞定所有事情,如此代码会越堆积越多,难于维护,功能扩展更是举步维艰。我们都需要有这种设计思想,每个化妆品部件各司其职,不做和自己不相关的事,然后把部件层层叠加,并根据需求组装成型,以达最终的装饰目的。