从毛胚房的装修说起
每个人拿到属于自己的毛胚房时都兴奋不已,左看看右量量,筹划着装修的桩桩件件,憧憬着未来的幸福家园。每个人都希望装修完全按照自己的设想走,无论风格还是造价预算。可是装修这个活并不好干,同样的毛胚房有很多种装修方案,装修过程中也不可避免发生计划不如变化快的情形,往往最终的效果和最初的设想并不一致,这就是生活的实际。
软件开发的某个阶段和装修房子像极了!系统的基本功能实现后(原型跑起来),相当于毛胚房建造完成,界面不美观,功能也不够完善,毛胚嘛!在接下来的软件“装修”过程中,Decorator 模式将发挥重大的作用。众所周知,我们实施房屋装修工程有两个基本条件和约束:第一,必须有个毛胚房,否则还装修什么啊!第二,不能拆除承重结构。软件的装修也是如此,基本功能和流程框架不会做大的改动,否则还不如推倒重来了。Decorator 设计模式正如房屋的装修,是在毛胚房的基础上层层 wrapper(包装),先刷刷墙面漆,再铺铺木地板,再购置家具布置一下等等。这一道道的装修工序,可以看作是对毛胚房层层包装,最后的装修效果,甚至让你忘记了毛胚房的样子!因此,Decorator 设计模式也被称为 Wrapper 设计模式。
Decorator 设计模式的特点
Decorator 设计模式正如毛胚房的装修,不会改变原毛胚房的基本框架,只是增加新的外观、功能等,且随着时间的推移,可以不断的实施装修工程:增加新的家具、根据心情换换新鲜的墙纸等等。在面向对象的程序设计中,扩展系统的原有功能也可以采用继承、组合的方式。继承也不会改变毛胚房(父类),但是由于装修工程的复杂和很多不可预测的改变,比如不同墙纸和地板样式的组合数量简直无法想想,难道我们要为每一种组合都定义一个子类吗?显然这是不现实的,即通过继承的方式来应对未来的功能和外观改变通常是吃力不讨好的事情。组合的方式也不可取,因为这要求不断的修改父类的结构,相当于对毛胚房大动干戈,房屋的可维护性和可靠性就大大降低了。
让我们回顾一下设计模式的重要原则:Classes should be open for extenstion, but closed for modification。Decorator 设计模式很好的诠释了这个原则。
Decorator 设计模式的 Java 实例
以房屋装修为例,依据 Decorator 设计模式的原则设计类图如下:
public interface Room { public String showRoom(); }
BlankRoom.java 就是毛胚房了。毛胚房也是房子啊,因此实现了 Room 接口的基本功能:
// 毛胚房,这是我们装修工程的基础 public class BlankRoom implements Room { @Override public String showRoom() { return "毛胚房"; } }
RoomDecorator 是所有 Decorator 类的父类,由于 RoomDecorator 通常不实现具体功能,因此设计为抽象类。
// 装修工程的模板 abstract public class RoomDecorator implements Room { // wrapper 的具体体现,每个独立的装修工序都是在上一个装修工序 // 的基础上进行的,装修就是这样层层包装完成的 protected Room roomToBeDecorated; public RoomDecorator(Room roomToBeDecorated) { this.roomToBeDecorated = roomToBeDecorated; } @Override public String showRoom() { // 委托(delegate) return roomToBeDecorated.showRoom(); } }
PaintedDecorator 类是 RoomDecorator 的子类,实现了房屋粉刷功能:
public class PaintedDecorator extends RoomDecorator { public PaintedDecorator(Room roomToBeDecorated) { super(roomToBeDecorated); } public String showRoom(){ doPainting(); return super.showRoom() + "刷墙漆"; } // 刷墙漆 private void doPainting(){} }
FlooredDecorator 类是 RoomDecorator 的子类,实现了铺地板的功能:
public class FlooredDecorator extends RoomDecorator { public FlooredDecorator(Room roomToBeDecorated) { super(roomToBeDecorated); } public String showRoom(){ doFlooring(); return super.showRoom() + "铺地板"; } // 铺地板 private void doFlooring(){} }
最后,写一个测试类,
public class TestClient { public static void main(String[] args) { // 毛胚房 Room blankRoom = new BlankRoom(); // 刷了墙的毛胚房 Room paintedRoom = new PaintedDecorator(new BlankRoom()); // 先刷墙再铺地板的毛胚房 // 注意到连续的 new 操作,这就是 wrapper,最内层的一般是毛胚房 Room paintedAndFlooredRoom = new FlooredDecorator(new PaintedDecorator(new BlankRoom())); // 先铺地板再刷墙的毛胚房 Room flooredAndPaintedRoom = new PaintedDecorator(new FlooredDecorator(new BlankRoom())); System.out.println(blankRoom.showRoom()); System.out.println(paintedRoom.showRoom()); System.out.println(paintedAndFlooredRoom.showRoom()); System.out.println(flooredAndPaintedRoom.showRoom()); } }
执行结果:
本文来于:http://www.ibm.com/developerworks/cn/java/j-lo-cdi-decorator-pattern/