[转] 把委托说透(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 Observer
34 {
35     public abstract void Update(Subject subject);
36 }
37
38 public class ConsoleObserver : Observer
39 {
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 Observer
30     {
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 : Observer
43     {
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 Program
55     {
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 : AbstractClass
16 {
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):委托与事件

时间: 2024-08-03 15:20:55

[转] 把委托说透(4):委托与设计模式的相关文章

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

在上一篇随笔中我们通过示例逐步引入了委托,并比较了委托和接口.本文将重点剖析委托的实质. 委托在本质上仍然是一个类,我们用 delegate 关键字声明的所有委托都继承自System.MulticastDelegate.后者又是继承自System.Delegate类,System.Delegate类则继承自System.Object.委托既然是一个类,那么它就可以被定义在任何地方,即可以定义在类的内部,也可以定义在类的外部. 正如很多资料上所说的,委托是一种类型安全的函数回调机制, 它不仅能够调

Net中委托之二多播委托

本篇主要讲解多播委托 1.多播委托的实例 public class MyDelegate { private delegate int NoParameterWithReturn();//1.声明委托 public static void Show() { NoParameterWithReturn method = new NoParameterWithReturn(ShowSomething);//2.委托的实例化 //多播委托 method += ShowSomething;//按顺序添加

委托、Lambda表达式、事件系列01,委托是什么,委托的基本用法,委托的Method和Target属性

委托是一个类. namespace ConsoleApplication1 { internal delegate void MyDelegate(int val); class Program { static void Main(string[] args) { } } } 使用Reflector查看委托的IL代码:○ 委托的确是一个类○ 委托的构造函数接收方法和类实例○ 而且是多播委托,可以用+=为委托变量赋值○ 委托内部使用Invoke方法触发方法○ BeginInvoke和EndInv

【转发】什么时候该用委托,为什么要用委托,委托有什么好处

好多人一直在问:什么时候该用委托,为什么要用委托,委托有什么好处.... 看完下面的文章你将茅塞顿开..(看不懂的直接TDDTDS) 概念虽然我不喜欢讲太多 我们直接先来YY 个场景:我很喜欢打游戏,但运气不好每次打游戏都会被主管看到,朱老板不喜欢他的员工在上班的时 间打游戏,所以朱老板就跟主管说:以后员工在打游戏,你就扣他20块钱. 这其实就是一个委托,朱老板委托主管一旦发现员工打游戏,就做一件事情. 程序该怎么写呢? 至少有2个类吧,主管与员工,主管有个方法扣钱,员工有个方法玩游戏,那么开始

C# 委托 (一)—— 委托、 泛型委托与Lambda表达式

C# 委托 (一)—— 委托. 泛型委托与Lambda表达式 2018年08月19日 20:46:47 wnvalentin 阅读数 2992 版权声明:此文乃博主之原创.鄙人才疏,望大侠斧正.此文可转载,然需明根以溯源. https://blog.csdn.net/wnvalentin/article/details/81840339 目录 1 委托的含义 2 委托声明.实例化和调用 2.1 委托的声明 2.2 委托的实例化 2.3 委托实例的调用 3 泛型委托 3.1 Func委托 3.2

c# 匿名方法(函数) 匿名委托 内置泛型委托 lamada

匿名方法:通过匿名委托 .lamada表达式定义的函数具体操作并复制给委托类型: 匿名委托:委托的一种简单化声明方式通过delegate关键字声明: 内置泛型委托:系统已经内置的委托类型主要是不带返回值的Action<T1,,,,Tn>和带返回值的Func<T1,,,Tn,Tresult> 实例代码 class demoFunc { /// <summary> /// 定义函数单条语句直接用lamada表达式 /// </summary> /// <p

jquery 委托 on() | off()删除委托 | one()只执行一次的委托

<1> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script src="jquer

委托-异步调用-泛型委托-匿名方法-Lambda表达式-事件

1. 委托 From: http://www.cnblogs.com/daxnet/archive/2008/11/08/1687014.html 类是对象的抽象,而委托则可以看成是函数的抽象.一个委托代表了具有相同参数列表和返回值的所有函数. [csharp] view plaincopy class Program { delegate int CalculateDelegate(int a, int b); int add(int a, int b) { return a + b; } s

委托和事件匿名委托

public delegate void maojiaodelegate (object Sender, EventArgs e); /// <summary> /// 触发对象 观察者 人醒来 /// </summary> public class BigMaster { private Mao _cat; public BigMaster(Mao cat) { _cat = cat; _cat.onjiao += new maojiaodelegate(onxinglaile)