首页 > 代码库 > [转] 把委托说透(4):委托与设计模式

[转] 把委托说透(4):委托与设计模式

委托与很多设计模式都有着千丝万缕的联系,在前面的随笔中已经介绍了委托与策略模式的联系,本节主要来讨论委托与其他两个模式:观察者模式和模板方法模式。

委托与观察者模式

在.NET中,很多设计模式得到了广泛应用,如foreach关键字实现了迭代器模式。同样的,.NET中也内置了观察者模式的实现方式,这种方式就是委托。

观察者模式的一般实现

网上可以找到很多资料介绍观察者模式的实现,我这里介绍一种简单的退化后的观察者模式,即Subject类为具体类,在其之上不再进行抽象。

 1 public class Subject 2 { 3     private List<Observer> observers = new List<Observer>(); 4  5     private string state; 6     public string State 7     { 8         set 9         {10             state = value;11             NotifyObservers();12         }13         get { return state; }14     }15 16     public void RegisterObserver(Observer ob)17     {18         observers.Add(ob);19     }20 21     public void RemoveObserver(Observer ob)22     {23         observers.Remove(ob);24     }25 26     public void NotifyObservers()27     {28         foreach (Observer ob in observers)29             ob.Update(this);30     }31 }32 33 public abstract class Observer34 {35     public abstract void Update(Subject subject);36 }37 38 public class ConsoleObserver : Observer39 {40     public ConsoleObserver(Subject subject)41     {42         subject.RegisterObserver(this);43     }44 45     public override void Update(Subject subject)46     {47         Console.WriteLine("Subject has changed its state : " + subject.State);48     }49 }50  

调用的方法很简单:

1 Subject subject = new Subject();2 Observer observer = new ConsoleObserver(subject);3 subject.State = "Kirin Yao";

Subject类维护一个列表,负责观察者的注册和移除。当其状态发生改变时,就调用NotifyObservers方法通知各个观察者。

 

观察者模式的委托实现

在.NET中,使用委托可以更简单更优雅地实现观察者模式。在上一篇随笔中,最后的示例其实就是一个观察者模式。MainForm为Subject,SubForm为Observer。当MainForm的状态发生改变时(即点击“传值”按钮时),SubForm作为观察者响应来自MainForm的变化。

与上例对应的,用委托实现的观察者模式的代码大致如下:

 1 namespace DelegateSample 2 { 3     class UpdateEventArgs : EventArgs { } 4  5     class Subject 6     { 7         private string state; 8  9         public string State 10         {11             get { return state; }12             set 13             {14                 state = value;15                 OnUpdate(new UpdateEventArgs());16             }17         }18 19         public event EventHandler<UpdateEventArgs> Update;20 21         private void OnUpdate(UpdateEventArgs e)22         {23             EventHandler<UpdateEventArgs> handler = Update;24             if (handler != null)25                 Update(this, e);26         }27     }28 29     abstract class Observer30     {31         public Subject Subject { get; set; }32 33         public Observer(Subject subject)34         {35             this.Subject = subject;36             this.Subject.Update += new EventHandler<UpdateEventArgs>(Subject_Update);37         }38 39         protected abstract void Subject_Update(object sender, UpdateEventArgs e);40     }41 42     class ConsoleObserver : Observer43     {44         public ConsoleObserver(Subject subject) : base(subject) { }45 46         protected override void Subject_Update(object sender, UpdateEventArgs e)47         {48             Subject subject = sender as Subject;49             if (subject != null)50                 Console.WriteLine("Subject has changed its state : " + subject.State);51         }52     }53 54     class Program55     {56         static void Main(string[] args)57         {58             Subject subject = new Subject();59             Observer ob = new ConsoleObserver(subject);60             subject.State = "Kirin Yao";61             Console.ReadLine();62         }63     }64 }

相比传统的观察者模式的实现方式(在Subject中维护一个Observer列表),使用委托避免了Subject与Observer之间的双向引用,Subject作为主题类,对观察者毫无所知,降低了耦合性,语法上也更加优雅。

委托与模板方法模式

模板方法模式封装了一段通用的逻辑,将逻辑中的特定部分交给子类实现。

 1 public abstract class AbstractClass 2 { 3     public void Arithmetic() 4     { 5         SubArithmeticA(); 6         SubArithmeticB(); 7         SubArithmeticC(); 8     } 9 10     protected abstract void SubArithmeticA();11     protected abstract void SubArithmeticB();12     protected abstract void SubArithmeticC();13 }14 15 public class ConcreteClass : AbstractClass16 {17     protected override void SubArithmeticA()18     {19         //...20     }21 22     protected override void SubArithmeticB()23     {24         //...25     }26 27     protected override void SubArithmeticC()28     {29         //...30     }31 }

然而这种继承方式的模板方法耦合度较高,特别是如果逻辑与其外部实现没有必然的从属关系的时候,用传统的模板方法就显得不那么合适了。

在某种程度上,委托可以看做是一个轻量级的模板方法实现方式,它将逻辑中的特定部分转交给注册到委托的方法来实现。从而替代了继承方式的模板方法模式中,在子类中实现特定逻辑的方式。

 1 public delegate void SubArithmetic(); 2  3 public class ConcreteClass 4 { 5     public void Arithmetic() 6     { 7         if (SubArithmetic != null) 8             SubArithmetic(); 9     }10 11     public SubArithmetic SubArithmetic { get; set; }12 }

而SubArithmetic的实现交给外部:

1 ConcreteClass concrete = new ConcreteClass();2 concrete.SubArithmetic = Program.SomeMethod;3 concrete.Arithmetic();

咋一看在客户端中编写委托的方法似乎还略显麻烦,但值得注意的是,匿名方法和Lambda表达式为我们提供了更加简便的委托语法。在函数式编程日益盛行的今天,我们应该为.NET提供的这种语言特性而感到庆幸。

总结

本文重点讨论委托与设计模式的关系,包括观察者模式和模板方法模式。您是否觉得委托与其他方法也有关系呢?不妨在回复中进行讨论。

到此为止,我们共发布了4篇随笔,讨论委托及其相关概念。其他三篇的链接如下:

把委托说透(1):开始委托之旅 委托与接口

把委托说透(2):深入理解委托

把委托说透(3):委托与事件

[转] 把委托说透(4):委托与设计模式