上回说到设计六原则,今天我们就拿装饰模式和代理模式来验证一下。
装饰模式,官方是这么解释的:动态的给一个对象添加额外的功能。说的很清楚吧,就好比国产凌凌漆的皮鞋,给它装上电池和风扇呢,它就变成了电吹风!
我们来看看装饰模式的UML图:
注意接口这个恶魔出现了,它躲在众多实现类身后向你伸出精神控制的触手,刺入你的大脑,在你的思想里植入一种叫做“面向接口编程”的病毒。从此你慢慢变得双眼无神、毛发脱落、肤色苍白,最终将彻底蜕变成一种叫做“架构尸”的半死不活的生物。
事到如今什么都拯救不了你啦,所以我们还是接着看装饰模式。ConcreteComponent是要扩展的类,它实现了接口Component。Decorator是扩展ConcreteComponent的,它也实现Component接口。Decorator怎样给ConcreteComponent添加额外功能呢?首先Decorator包含一个Component的对象,然后它的sampleOperation方法可以这样实现:
@Override
public void sampleOperation() {
System.out.println(“我要额外干点啥!”);
component.sampleOperation();
System.out.println(“僵尸吃掉了你的脑子!咦,我为什么要说这个?”);
}
假设现在你中的“设计魔尸”毒还不够深,大脑还有自主思考的能力,那么你就要问了:“为了加两行代码弄出个类来了,何必这么麻烦?我直接改ConcreteComponent的sampleOperation方法!”
好的!我就是要你这样想!你已堕入彀中,我这早就准备好六大原则准备糊你熊脸呢!还记得开闭原则说的什么:对扩展开放,对修改关闭!嘿嘿,少年,乖乖献出你的膝盖吧。
这里对开闭原则补充两句:对修改关闭,不是说不让修改代码,还没经过测试和发布的代码当然要不断修改,不然发现bug怎么办。开闭原则是针对已release的代码升级来说的,尽量采用装饰模式来扩展原有类的功能。即使是已release的代码,也不是绝对不能修改的,当年JDK为了泛型,把全部Collection实现都重写了一遍。
这时又一位少年跳出来喊道:“老狗休要得意,我继承ConcreteComponent并重写sampleOperation方法难道不可?”老狗狞笑着从背后取出合成复用原则道:“少年还是too simple,too naïve 。难道忘了还有这个宝贝吗?”
所以血气方刚的少年们啊,不管你有多少剑走偏锋的招式,都不要忘了还有六大原则这面金刚盾。二十三种设计模式一定是满足六原则的,少年你可以放心使用。那是不是不能有超出这二十三中模式之外的设计出现?绝对不是,编程还有一条基本原则:用最简单的方法实现。但你在这样做的时候,一定要再三的思考和检验,是否违反了某条原则。
本节我们还要讲一个与装饰模式很相识的模式:代理模式。下面来看代理模式的UML图:
眼尖的少年已经跳起来喊了:“卧槽怎么跟装饰模式一模一样!”对,你没看错,确实两种模式非常相识。都是实现同一个接口的两个类,第二个类对第一个类的接口方法有所扩展。
不过细看两者还是有些细微差别的:装饰模式的Decorator持有的不是ConcreteComponent类的对象,而是Component接口。而ProxyObject持有的就是RealObject类的对象。那么Decorator是如何获得ConcreteComponent类的对象呢,一般是在构造方法中传入,像这样:
public Decorator(Component component) {
this.component= component;
}
Component component = new ConcreteComponent();
Decorator decorator = newDecorator(component);
那么除了具体实现细节略有不同,装饰模式和代理模式到底有什么根本性的区别呢?或者说装饰模式为什么不能完全取代代理模式呢?说实话老狗我也没想通这里面的缘由,只能说是这两种模式的目的不同:装饰模式是为了扩展一个类的功能,代理模式是提供对一个类的间接访问。
最后提一句,Java中的各种InputStream类,是典型的装饰模式的实现,有兴趣的同学可以去看看Java的I/O库的源码。
欢迎扫码关注我的微信公众号
看爽了请打赏!