装饰(Decorator)模式是对象结构模式,GOF对它的作用描述为:动态地给一个对象添加一些额外的职责,就增加功能来说,Decorator模式比生成子类更为灵活。现在直接给出GOF著作中的Decorator模式结构图:
实现案例是学习设计模式的好办法,GOF一书中给了一个例子,就是“图形用户界面”设计的问题,一个图形用户界面工具箱允许你对任意一个用户界面组件添加一些特性,例如边框,或是一些行为,例如窗口滚动。 可以使用继承实现,但方法太过死板,因为通过继承实现的边框,它的选择是静态的,用户不能控制对组件加边框的方式和时机。记住:继承是强关联关系。较为灵活的办法是将组件放到一个对象中,由这个对象为组件添加边框。而这个嵌入的对象就是装饰。类图如下图:
由给定的类图结构,设计以下相应的代码,如下:
1 abstract class VisualComponent{ 2 public VisualComponent(){}; 3 abstract void Draw(); 4 abstract void Resize(); 5 } 6 abstract class Decorator extends VisualComponent{ 7 private VisualComponent v; 8 public Decorator(VisualComponent v){this.v=v;}; 9 void Draw(){v.Draw();}; 10 void Resize(){v.Resize();}; 11 } 12 class TextView extends VisualComponent{ 13 public TextView(){}; 14 public void Draw(){ 15 System.out.println("Draw a TextView"); 16 } 17 public void Resize(){ 18 System.out.println("Reset the text's size"); 19 } 20 } 21 class BorderDecorator extends Decorator{ 22 private int width; 23 public BorderDecorator(VisualComponent v,int width){ 24 super(v); 25 this.width=width; 26 } 27 private void DrawBorder(int width){ 28 System.out.println("Decorate it with a line whose width is "+width); 29 } 30 public void Draw(){ 31 super.Draw(); 32 DrawBorder(width); 33 } 34 } 35 36 public class Test{ 37 38 public static void main(String[] args){ 39 40 new BorderDecorator(new TextView(),10).Draw(); 41 } 42 }
装饰模式典型的创建对象的过程如下代码所示。
1 new Decorator1( 2 new Decorator2( 3 new Decorator3( 4 new ConcreteComponent() 5 ) 6 ) 7 );
使用装饰模式要注意以下几点:
1、接口的一致性。装饰对象必须和它所装饰的Component的接口要一致,组件类和装饰类必须有一个公共的父类。
2、保持Component类的简单性。Component应集中定义接口(也就是方法),而不是用于存储数据,应该把数据的定义延迟到子类中。