扩展系统功能——装饰模式(三)

12.3 完整解决方案

为了让系统具有更好的灵活性和可扩展性,克服继承复用所带来的问题,Sunny公司开发人员使用装饰模式来重构图形界面构件库的设计,其中部分类的基本结构如图12-4所示:

扩展系统功能——装饰模式(三) - 图1

图12-4 图形界面构件库结构图

在图12-4中,Component充当抽象构件类,其子类Window、TextBox、ListBox充当具体构件类,Component类的另一个子类ComponentDecorator充当抽象装饰类,ComponentDecorator的子类ScrollBarDecorator和BlackBorderDecorator充当具体装饰类。完整代码如下所示:

  1. //抽象界面构件类:抽象构件类,为了突出与模式相关的核心代码,对原有控件代码进行了大量的简化
  2. abstract class Component
  3. {
  4. public abstract void display();
  5. }
  6. //窗体类:具体构件类
  7. class Window extends Component
  8. {
  9. public void display()
  10. {
  11. System.out.println("显示窗体!");
  12. }
  13. }
  14. //文本框类:具体构件类
  15. class TextBox extends Component
  16. {
  17. public void display()
  18. {
  19. System.out.println("显示文本框!");
  20. }
  21. }
  22. //列表框类:具体构件类
  23. class ListBox extends Component
  24. {
  25. public void display()
  26. {
  27. System.out.println("显示列表框!");
  28. }
  29. }
  30. //构件装饰类:抽象装饰类
  31. class ComponentDecorator extends Component
  32. {
  33. private Component component; //维持对抽象构件类型对象的引用
  34. public ComponentDecorator(Component component) //注入抽象构件类型的对象
  35. {
  36. this.component = component;
  37. }
  38. public void display()
  39. {
  40. component.display();
  41. }
  42. }
  43. //滚动条装饰类:具体装饰类
  44. class ScrollBarDecorator extends ComponentDecorator
  45. {
  46. public ScrollBarDecorator(Component component)
  47. {
  48. super(component);
  49. }
  50. public void display()
  51. {
  52. this.setScrollBar();
  53. super.display();
  54. }
  55. public void setScrollBar()
  56. {
  57. System.out.println("为构件增加滚动条!");
  58. }
  59. }
  60. //黑色边框装饰类:具体装饰类
  61. class BlackBorderDecorator extends ComponentDecorator
  62. {
  63. public BlackBorderDecorator(Component component)
  64. {
  65. super(component);
  66. }
  67. public void display()
  68. {
  69. this.setBlackBorder();
  70. super.display();
  71. }
  72. public void setBlackBorder()
  73. {
  74. System.out.println("为构件增加黑色边框!");
  75. }
  76. }

编写如下客户端测试代码:

  1. class Client
  2. {
  3. public static void main(String args[])
  4. {
  5. Component component,componentSB; //使用抽象构件定义
  6. component = new Window(); //定义具体构件
  7. componentSB = new ScrollBarDecorator(component); //定义装饰后的构件
  8. componentSB.display();
  9. }
  10. }

编译并运行程序,输出结果如下:

  1. 为构件增加滚动条!
  2. 显示窗体!

在客户端代码中,我们先定义了一个Window类型的具体构件对象component,然后将component作为构造函数的参数注入到具体装饰类ScrollBarDecorator中,得到一个装饰之后对象componentSB,再调用componentSB的display()方法后将得到一个有滚动条的窗体。如果我们希望得到一个既有滚动条又有黑色边框的窗体,不需要对原有类库进行任何修改,只需将客户端代码修改为如下所示:

  1. class Client
  2. {
  3. public static void main(String args[])
  4. {
  5. Component component,componentSB,componentBB; //全部使用抽象构件定义
  6. component = new Window();
  7. componentSB = new ScrollBarDecorator(component);
  8. componentBB = new BlackBorderDecorator(componentSB); //将装饰了一次之后的对象继续注入到另一个装饰类中,进行第二次装饰
  9. componentBB.display();
  10. }
  11. }

编译并运行程序,输出结果如下:

  1. 为构件增加黑色边框!
  2. 为构件增加滚动条!
  3. 显示窗体!

我们可以将装饰了一次之后的componentSB对象注入另一个装饰类BlackBorderDecorator中实现第二次装饰,得到一个经过两次装饰的对象componentBB,再调用componentBB的display()方法即可得到一个既有滚动条又有黑色边框的窗体。

如果需要在原有系统中增加一个新的具体构件类或者新的具体装饰类,无须修改现有类库代码,只需将它们分别作为抽象构件类或者抽象装饰类的子类即可。与图12-2所示的继承结构相比,使用装饰模式之后将大大减少了子类的个数,让系统扩展起来更加方便,而且更容易维护,是取代继承复用的有效方式之一。