来源:懒得安分 链接:http://www.cnblogs.com/landeanfen/p/4710174.html
前言:这篇打算从设计模式的角度去解析下委托的使用。我们知道使用委托可以实现对象行为(方法)的动态绑定,从而提高设计的灵活性。上次说过,方法可以理解为委托的实例,站在方法的层面,委托实例的一个非常有用的特性是它既不知道,也不关心其封装方法所属类的详细信息,对它来说最重要的是这些方法与该委托的参数和返回值的兼容性。即只要方法的返回类型和参数表是相同的,则方法与委托类型兼容,方法的名称及方法所属类等信息委托是不关心的。有一定编程经验的大侠们肯定都接触过设计模式,其实设计模式大多数都是面向对象多态特性的体现,通过重写子类方法去展现不同的设计需求,这样看,既然是方法重写,那么方法的参数类型和返回值类型肯定是一致的,这是不是和委托的实例十分相似,这样说来,我们通过多态去实现的设计模式是否可以用委托的形式去代替。博主觉得,为了更好的理解委托,可以从这方面着手试试。。。
此篇简单抽取了几个设计模式分别按照多态和委托的方式去实现,当然这里的重点并不是讲设计模式,而是为了使读者更好地理解委托。所以设计模式的很多细节,本篇可能会略过。
一、简单工厂模式:本篇就借助计算器的例子加以说明。
1、多态实现简单工厂模式。
class Program2 { static void Main(string[] args) { //1.使用多态实现简单工厂模式 int x = 8, y = 2; var iRes1 = GetObject('+').Compute(x, y); var iRes2 = GetObject('-').Compute(x, y); var iRes3 = GetObject('*').Compute(x, y); var iRes4 = GetObject('/').Compute(x, y); Console.WriteLine(iRes1); Console.WriteLine(iRes2); Console.WriteLine(iRes3); Console.WriteLine(iRes4); Console.ReadKey(); } static Calculator GetObject(string type) { Calculator oRes = null; switch (type) { case '+': oRes = new Add(); break; case '-': oRes = new Subtract(); break; case '*': oRes = new Multiply(); break; case '/': oRes = new Divide(); break; } return oRes; } } public class Calculator { public virtual int Compute(int x, int y) { return 0; } } public class Add : Calculator { public override int Compute(int x, int y) { return x + y; } } public class Subtract : Calculator { public override int Compute(int x, int y) { return x - y; } } public class Multiply : Calculator { public override int Compute(int x, int y) { return x * y; } } public class Divide : Calculator { public override int Compute(int x, int y) { if (y == 0) { return 0; } return x / y; } }
代码应该很容易看懂,直接通过方法的重写去实现,在此就不过多讲解。
2、委托方式实现简单工厂模式。
class Program2 { static void Main(string[] args) { #region 2.委托实现简单工厂模式 int x = 8, y = 2; var oCalculator = new Calculator(); var iRes1 = oCalculator.Compute(x, y, oCalculator.Add); //将方法作为参数传下去 var iRes2 = oCalculator.Compute(x, y, oCalculator.Subtract); var iRes3 = oCalculator.Compute(x, y, oCalculator.Multiply); var iRes4 = oCalculator.Compute(x, y, oCalculator.Divide); Console.WriteLine(iRes1); Console.WriteLine(iRes2); Console.WriteLine(iRes3); Console.WriteLine(iRes4); #endregion Console.ReadKey(); } } public delegate int DelegateCalculator(int x, int y); public class Calculator { //将方法的实例传递进来,在Compute方法里面执行 public int Compute(int x, int y, DelegateCalculator calculator) { return calculator(x, y); } public int Add(int x, int y) { return x + y; } public int Subtract(int x, int y) { return x - y; } public int Multiply(int x, int y) { return x * y; } public int Divide(int x, int y) { if (y == 0) { return 0; } return x / y; } }
这里需要定义四个实现方法Add、Subtract、Multiply、Divide,而不用在意这四个方法在哪个类下面,只要这四个方法的的参数和返回值和委托的定义保持一致即可。这也验证了上面说的 “站在方法的层面,委托实例的一个非常有用的特性是它既不知道,也不关心其封装方法所属类的详细信息,对它来说最重要的是这些方法与该委托的参数和返回值的兼容性” 。两种方式得到的结果是相同的:
二、观察者模式:观察者模式最典型的场景就是订阅者和订阅号的场景
1、纯多态方式实现观察者模式:这种代码园子里面非常多。
class Program3 { static void Main(string[] args) { // 具体主题角色通常用具体自来来实现 ConcreteSubject subject = new ConcreteSubject(); subject.Attach(new ConcreteObserver(subject, 'Observer A')); subject.Attach(new ConcreteObserver(subject, 'Observer B')); subject.Attach(new ConcreteObserver(subject, 'Observer C')); subject.SubjectState = 'Ready'; subject.Notify(); Console.Read(); } } //抽象主题类 public abstract class Subject { private IList observers = new List(); /// /// 增加观察者 /// /// public void Attach(Observer observer) { observers.Add(observer); } /// /// 移除观察者 /// /// public void Detach(Observer observer) { observers.Remove(observer); } /// /// 向观察者(们)发出通知 /// public void Notify() { foreach (Observer o in observers) { o.Update(); } } } //具体主题类 public class ConcreteSubject : Subject { private string subjectState; /// /// 具体观察者的状态 /// public string SubjectState { get { return subjectState; } set { subjectState = value; } } } //抽象观察者类 public abstract class Observer { public abstract void Update(); } //具体观察者 public class ConcreteObserver : Observer { private string observerState; private string name; private ConcreteSubject subject; /// /// 具体观察者用一个具体主题来实现 /// public ConcreteSubject Subject { get { return subject; } set { subject = value; } } public ConcreteObserver(ConcreteSubject subject, string name) { this.subject = subject; this.name = name; } /// /// 实现抽象观察者中的更新操作 /// public override void Update() { observerState = subject.SubjectState; Console.WriteLine('The observer's state of {0} is {1}', name, observerState); } }
可以看到虽然已经很好的实现了观察者Observer 和主题Subject之间的分离。但是Subject的内部还是有对观察者的调用:
public void Notify() { foreach (Observer o in observers) { o.Update(); } }
2、多态和委托实现观察者模式。
class Program3 { static void Main(string[] args) { // 具体主题角色通常用具体自来来实现 ConcreteSubject subject = new ConcreteSubject(); //传入的只是观察者的通过方法。 subject.Attach(new ConcreteObserver(subject, 'Observer A').Update); subject.Attach(new ConcreteObserver(subject, 'Observer B').Update); subject.Attach(new ConcreteObserver(subject, 'Observer C').Update); subject.SubjectState = 'Ready'; subject.Notify(); Console.Read(); } } public delegate void ObserverDelegate(); //抽象主题类 public abstract class Subject { public ObserverDelegate observedelegate; /// /// 增加观察者 /// /// public void Attach(ObserverDelegate observer) { observedelegate += observer; } /// /// 移除观察者 /// /// public void Detach(ObserverDelegate observer) { observedelegate -= observer; } /// /// 向观察者(们)发出通知 /// public void Notify() { if (observedelegate != null) { observedelegate(); } } } //具体主题类 public class ConcreteSubject : Subject { private string subjectState; /// /// 具体观察者的状态 /// public string SubjectState { get { return subjectState; } set { subjectState = value; } } } //具体观察者 public class ConcreteObserver { private string observerState; private string name; private ConcreteSubject subject; /// /// 具体观察者用一个具体主题来实现 /// public ConcreteSubject Subject { get { return subject; } set { subject = value; } } public ConcreteObserver(ConcreteSubject subject, string name) { this.subject = subject; this.name = name; } /// /// 实现抽象观察者中的更新操作 /// public void Update() { observerState = subject.SubjectState; Console.WriteLine('The observer's state of {0} is {1}', name, observerState); } }
得到结果:
这样设计的优势:
(1)将通知的方法Update通过委托的形式传入主题对象。这样主题对象Subject就完全和观察者隔离。更好地实现了低耦合。
(2)减少了观察者抽象类的定义。使整个设计更加精简。
(3)如果将设计更进一步,观察者这边自定义delegate void ObserverDelegate()这种类型的方法。比如需要执行Update()方法之后还要记录一个日志的操作。如:
//具体观察者 public class ConcreteObserver { private string observerState; private string name; private ConcreteSubject subject; /// /// 具体观察者用一个具体主题来实现 /// public ConcreteSubject Subject { get { return subject; } set { subject = value; } } public ConcreteObserver(ConcreteSubject subject, string name) { this.subject = subject; this.name = name; } /// /// 实现抽象观察者中的更新操作 /// public void Update() { observerState = subject.SubjectState; Console.WriteLine('The observer's state of {0} is {1}', name, observerState); } public void Log() { Console.WriteLine('Log:Update方法执行完成'); } }
那么在客户端调用时只需要将Log方法以委托的形式传入即可:
static void Main(string[] args) { // 具体主题角色通常用具体自来来实现 ConcreteSubject subject = new ConcreteSubject(); //传入的只是观察者的通过方法。 var obj = new ConcreteObserver(subject, 'Observer A'); subject.Attach(obj.Update); subject.Attach(obj.Log); subject.SubjectState = 'Ready'; subject.Notify(); Console.Read(); }
是不是显得更灵活一点。如果是纯多态的方式,由于Subject里面指定了调用Update()方法,所以当需要增加Log方法的时候代码的改变量要大。
|