博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

装饰(Decorator)模式

Posted on 2007-02-05 16:53  微尘  阅读(283)  评论(0)    收藏  举报


意图:

    Decorator模式采用对象组合而非继承的手法,实现了在运行时动态的扩展对象功能的能力,而且可以根据需要扩展多个功能,避免了单独使用继承带来的 “灵活性差”和“多子类衍生问题”。同时它很好地符合面向对象设计原则中“优先使用对象组合而非继承”和“开放-封闭”原则。

结构:

    装饰模式的类图如下图所示:


 


在装饰模式中的各个角色有:

  • 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
  • 具体构件(Concrete Component)角色:定义一个将要接收附加责任的类。
  • 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
  • 具体装饰(Concrete Decorator)角色:负责给构件对象"贴上"附加的责任。 

Decorator模式的几个要点(李建忠老师讲义):

  1. 通过采用组合、而继承的手法,Decorator模式实现了在运行时动态地扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。
  2. Component类在Decorator模式中充当抽象接口的角色,不应该去实现具体的行为。而且Decorator类对于Component类 应该透明--换言之Component类无需知道Decorator类,Decorator类是从外部来扩展Component类的功能。
  3. Decorator类在接口上表现为is-a Component的继承关系,即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另外一个Component类。我们可以使用一个或者多个Decorator对象来“装 饰”一个Component对象,且装饰后的对象仍然是一个Component对象。
  4. Decorator模式并非解决“多子类衍生的多继承”问题,Decorator模式应用的要点在于解决“主体类在多个方向上的扩展功能”--是为“装饰”的含义。

 

示意性代码:


 1  // Decorator pattern -- Structural example
 2 
 3 using System;
 4 
 5 namespace DoFactory.GangOfFour.Decorator.Structural
 6 {
 7 
 8   // MainApp test application
 9 
10   class MainApp
11   {
12     static void Main()
13     {
14       // Create ConcreteComponent and two Decorators
15       ConcreteComponent c = new ConcreteComponent();
16       ConcreteDecoratorA d1 = new ConcreteDecoratorA();
17       ConcreteDecoratorB d2 = new ConcreteDecoratorB();
18 
19       // Link decorators
20       d1.SetComponent(c);
21       d2.SetComponent(d1);
22 
23       d2.Operation();
24 
25       // Wait for user
26       Console.Read();
27     }
28   }
29 
30   // "Component"
31 
32   abstract class Component
33   {
34     public abstract void Operation();
35   }
36 
37   // "ConcreteComponent"
38 
39   class ConcreteComponent : Component
40   {
41     public override void Operation()
42     {
43       Console.WriteLine("ConcreteComponent.Operation()");
44     }
45   }
46 
47   // "Decorator"
48 
49   abstract class Decorator : Component
50   {
51     protected Component component;
52 
53     public void SetComponent(Component component)
54     {
55       this.component = component;
56     }
57 
58     public override void Operation()
59     {
60       if (component != null)
61       {
62         component.Operation();
63       }
64     }
65   }
66 
67   // "ConcreteDecoratorA"
68 
69   class ConcreteDecoratorA : Decorator
70   {
71     private string addedState;
72 
73     public override void Operation()
74     {
75       base.Operation();
76       addedState = "New State";
77       Console.WriteLine("ConcreteDecoratorA.Operation()");
78     }
79   }
80 
81   // "ConcreteDecoratorB"
82 
83   class ConcreteDecoratorB : Decorator
84   {
85     public override void Operation()
86     {
87       base.Operation();
88       AddedBehavior();
89       Console.WriteLine("ConcreteDecoratorB.Operation()");
90     }
91 
92     void AddedBehavior()
93     {
94     }
95   }
96 }
97 

.net中的装饰模式实例(Stream):

    结构图:

   

    可以看到BufferedStream、CryptoStream其实就是两个包装类,这里的Decorator模式省略了抽象装饰模式(Decorator),示例代码如下:

 1 class Program
 2 {
 3  public static void Main(string[] args)
 4  {
 5   MemoryStream ms =new MemoryStream(new byte[] { 100,456,864,222,567});
 6 
 7   //扩展了缓冲的功能
 8 
 9   BufferedStream buff = new BufferedStream(ms);
10 
11   //扩展了缓冲,加密的功能
12 
13   CryptoStream crypto = new CryptoStream(buff);
14  }
15 }

查看BufferedStream类的参考代码,可以看到BufferedStream类继承了Stream,并在现有流上增加了缓存功能。部分代码如下:
 1 using System;
 2 using System.Runtime.InteropServices;
 3 
 4 namespace System.IO
 5 {
 6     // 摘要:
 7     //     给另一流上的读写操作添加一个缓冲层。无法继承此类。
 8     [ComVisible(true)]
 9     public sealed class BufferedStream : Stream
10     {
11         // 摘要:
12         //     使用默认的缓冲区大小 4096 字节初始化 System.IO.BufferedStream 类的新实例。
13         //
14 
15         public BufferedStream(Stream stream);
16         //
17         // 摘要:
18         //     使用指定的缓冲区大小初始化 System.IO.BufferedStream 类的新实例。
19         //
20 
21         public BufferedStream(Stream stream, int bufferSize);
22 
23         // 摘要:
24         //     获取一个值,该值指示当前流是否支持读取。
25         //
26         public override bool CanRead { get; }
27         public override bool CanSeek { get; }
28         public override bool CanWrite { get; }
29         public override long Length { get; }
30         public override long Position { getset; }
31 
32         protected override void Dispose(bool disposing);
33         //
34         // 摘要:
35         //     清除该流的所有缓冲区,使得所有缓冲的数据都被写入到基础设备。
36         //
37         public override int Read(byte[] array, int offset, int count);
38         //
39         // 摘要:
40         //     从基础流中读取一个字节,并返回转换为 int 的该字节;或者如果从流的末尾读取则返回 -1。
41         //
42         public override int ReadByte();
43         //
44         // 摘要:
45         //     设置当前缓冲流中的位置。
46         //
47 
48         public override long Seek(long offset, SeekOrigin origin);
49         //
50         // 摘要:
51         //     设置缓冲流的长度。
52         //
53 
54         public override void SetLength(long value);
55         //
56         // 摘要:
57         //     将字节复制到缓冲流,并将缓冲流内的当前位置前进写入的字节数。
58         //
59 
60         public override void Write(byte[] array, int offset, int count);
61         //
62         // 摘要:
63         //     将一个字节写入缓冲流的当前位置。
64         //
65 
66         public override void WriteByte(byte value);
67     }
68 }

实际应用:

   
适用场合:     
  1. 需要扩展一个类的功能,或给一个类增加附加责任。
  2. 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
  3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变得不现实。

 

    实例(为用户登录行为增加权限验证的职责和添加日志记录功能):

    结构图:

   

实例代码:
1 public class User
2 {
3  public virtual void SignIn()
4  {
5   Console.WriteLine(”The User Sign In.”);
6  }
7 }

抽象类SignInDecorator的代码如下所示:
 1 public abstract SignInDecorator:User
 2 {
 3  private User m_user;
 4  public User User
 5  {
 6   get {return m_user;}
 7   set {m_user = value;}
 8  }
 9  public override void SignIn()
10  {
11   if (m_user != null)
12   {
13    m_user.SignIn();
14   }
15  }
16 }

而SignInDecorator的子类SecuritySignInDecorator (扩展验证功能)定义则如下:
 1 public class SecuritySignInDecorator:SignInDecorator
 2 {
 3  public override void SignIn()
 4  {
 5   if (IsValid())
 6   {
 7    base.SignIn();
 8   }
 9   else
10   {
11    throw new NotAuthorizationException();
12   }
13  }
14  private bool IsValid()
15  {
16   //略;
17   return true;
18  }
19 }

而SignInDecorator的子类LoggingSignInDecorator (增加日志功能)定义则如下:
 1 public class LoggingSignInDecorator:SignInDecorator
 2 {
 3  public override void SignIn()
 4  {
 5   base.SignIn();
 6   Logging();  
 7  }
 8  private void Logging()
 9  {
10   //略;
11  }
12 }



参考文献:
《.net与设计模式》
《C#面向对象设计模式纵横谈系列课程》
《java与模式》等
当然还有博客园中众多前辈的随笔,这里就不一一指出还望见谅……