假设咱们是一个优惠券提供平台,故事就发生在顾客在咱们平台采购完成支付成功后。git
支付完成后平台要进行的一些操做:app
短信通知客户已经生成订单异步
增长顾客的积分async
开始按订单需求制券ide
。。。(可能会有许多操做)3d
接下来就是将故事以代码的形式展示出来。。。code
咱们将上述故事转化为代码中的对象分别是: 支付成功 PaySuccessSubject、短信通知 MessageObserver、积分增长 BonusObserver、制券 CouponObserver。server
当支付成功PaySuccessSubject后,要通知到MessageObserver,BonusObserver,CouponObserver这三个对象,为了实现上面这个需求,将采用观察者模式(发布-订阅)对象
观察者模式又叫发布-订阅(Publish/Subscribe)模式,定义了一种一对多的依赖关系,让多个观察者对象同时 监听某一个主题对象。当主题对象在状态发生变化时,通知全部观察者对象,使他们可以本身更新本身。blog
Subject类,把全部观察者对象的引用保存在一个集合了,每一个通知者均可以有任何数量的观察者。抽象通知者提供 能够增长和删除观察者对象的接口。
/// <summary> /// 抽象通知者 /// </summary> public abstract class Subject { /// <summary> /// 观察者集合 /// </summary> protected List<IObserver> observers = new List<IObserver>(); public string State { get; set; } /// <summary> /// 添加观察者 /// </summary> /// <param name="observer">观察者</param> public void Attach(IObserver observer) { observers.Add(observer); } /// <summary> /// 删除观察者 /// </summary> /// <param name="observer">观察者</param> public void Detach(IObserver observer) { observers.Remove(observer); } /// <summary> /// 通知 /// </summary> /// <returns></returns> public void Notify() { foreach (var observer in observers) { observer.Update(); } } }
PaySuccessSubject类,具体的通知者,给全部登记过的观察者发出通知。
/// <summary> /// 支持成功通知者 /// </summary> public class PaySuccessSubject : Subject { }
Observer类,抽象观察者,为全部的具体的观察者定义一个接口,通常用抽象类或接口实现。一般包含一个Update()更新方法。
/// <summary> /// 抽象观察 /// </summary> public abstract class Observer { public abstract void Update(); }
MessageObserver、BonusObserver、CouponObserver具体的观察者类,实现更新接口,以便自己的状态与主题的状态相协调。
/// <summary> /// 短信观察者 /// </summary> public class MessageObserver : Observer { public Subject Subject { get; set; } public MessageObserver(Subject subject) { Subject = subject; } public override void Update() { Console.WriteLine($"{Subject.State}:短信通知了..."); } } /// <summary> /// 积分观察者 /// </summary> public class BonusObserver : Observer { public Subject Subject { get; set; } public BonusObserver(Subject subject) { Subject = subject; } public override void Update() { Console.WriteLine($"{Subject.State}:积分增长了..."); } } /// <summary> /// 券观察者 /// </summary> public class CouponObserver : Observer { public Subject Subject { get; set; } public CouponObserver(Subject subject) { Subject = subject; } public override void Update() { Console.WriteLine($"{Subject.State}:开始制券了..."); } }
客户端代码
private static void Main(string[] args) { var subject = new PaySuccessSubject(); var observer1 = new CouponObserver(subject); var observer2 = new MessageObserver(subject); var observer3 = new BonusObserver(subject); //添加订阅 subject.Attach(observer1); subject.Attach(observer2); subject.Attach(observer3); //发布通知 subject.State = "星巴克10十元券采购成功"; subject.Notify(); Console.WriteLine("\n\nHappy Ending~"); Console.ReadLine(); }
结果显示
code review后发现,在通知给观察者时,是顺序执行,若是其中一个观察者卡顿或者错误,会致使其余观察者卡克,因此咱们应该采用异步方式。
下面咱们将模拟 制券过程耗时增长,但不影响通知其余观察者。直接上代码:
/// <summary> /// 抽象观察 /// </summary> public abstract class Observer { public abstract Task UpdateAsync(); } /// <summary> /// 短信观察者 /// </summary> public class MessageObserver : Observer { public Subject Subject { get; set; } public MessageObserver(Subject subject) { Subject = subject; } public override Task UpdateAsync() { Console.WriteLine($"{Subject.State}:短信通知了..."); return Task.CompletedTask; } } /// <summary> /// 积分观察者 /// </summary> public class BonusObserver : Observer { public Subject Subject { get; set; } public BonusObserver(Subject subject) { Subject = subject; } public override Task UpdateAsync() { Console.WriteLine($"{Subject.State}:积分增长了..."); return Task.CompletedTask; } } /// <summary> /// 券观察者 /// </summary> public class CouponObserver : Observer { public Subject Subject { get; set; } public CouponObserver(Subject subject) { Subject = subject; } public override async Task UpdateAsync() { Console.WriteLine($"{Subject.State}:开始制券..."); //模拟制券耗时 await Task.Delay(3000); Console.WriteLine($"{Subject.State}:制券完成..."); } } /// <summary> /// 抽象通知者 /// </summary> public abstract class Subject { /// <summary> /// 观察者集合 /// </summary> protected List<Observer> observers = new List<Observer>(); public string State { get; set; } /// <summary> /// 添加观察者 /// </summary> /// <param name="observer">观察者</param> public void Attach(Observer observer) { observers.Add(observer); } /// <summary> /// 删除观察者 /// </summary> /// <param name="observer">观察者</param> public void Detach(Observer observer) { observers.Remove(observer); } /// <summary> /// 通知 /// </summary> /// <returns></returns> public Task Notify() { foreach (var observer in observers) { observer.UpdateAsync(); } return Task.CompletedTask; } }
客户端端代码:
private static async Task Main(string[] args) { var subject = new PaySuccessSubject(); var observer1 = new CouponObserver(subject); var observer2 = new MessageObserver(subject); var observer3 = new BonusObserver(subject); //添加订阅 subject.Attach(observer1); subject.Attach(observer2); subject.Attach(observer3); //发布通知 subject.State = "星巴克10十元券采购成功"; await subject.Notify(); Console.WriteLine("\n\nHappy Ending~"); Console.ReadLine(); }
结果显示:
现实开发中,不少观察者对象共同继承或者实现同一个抽象观察者,不合适;而且全部观察者对象的操做方法统一叫一个 Update(),达不到望文生义的效果,因此咱们对观察者模式再次进行升级,使用委托来替换掉抽象观察者,
直接上代码:
/// <summary> /// 短信观察者 /// </summary> public class MessageObserver { public ISubject Subject { get; set; } public MessageObserver(ISubject subject) { Subject = subject; } /// <summary> /// 发送短信 /// </summary> /// <returns></returns> public Task SendMessageAsync() { Console.WriteLine($"{Subject.State}:短信通知了..."); return Task.CompletedTask; } } /// <summary> /// 积分观察者 /// </summary> public class BonusObserver { public ISubject Subject { get; set; } public BonusObserver(ISubject subject) { Subject = subject; } /// <summary> /// 添加积分 /// </summary> /// <returns></returns> public Task AddBonusAsync() { Console.WriteLine($"{Subject.State}:积分增长了..."); return Task.CompletedTask; } } /// <summary> /// 券观察者 /// </summary> public class CouponObserver { public ISubject Subject { get; set; } public CouponObserver(ISubject subject) { Subject = subject; } /// <summary> /// 制券 /// </summary> /// <returns></returns> public async Task MakeCouponAsync() { Console.WriteLine($"{Subject.State}:开始制券..."); //模拟制券耗时 await Task.Delay(3000); Console.WriteLine($"{Subject.State}:制券完成..."); } } /// <summary> /// 抽象通知者 /// </summary> public interface ISubject { /// <summary> /// 通知 /// </summary> /// <returns></returns> public Task Notify(); public string State { get; set; } } /// <summary> /// 支持成功通知者 /// </summary> public class PaySuccessSubject : ISubject { public Func<Task> Update; public string State { get; set; } public Task Notify() { Update(); return Task.CompletedTask; } } }
客户端调用:
internal class Program { private static async Task Main(string[] args) { var subject = new ObserverDelegate.PaySuccessSubject(); var observer1 = new ObserverDelegate.CouponObserver(subject); var observer2 = new ObserverDelegate.MessageObserver(subject); var observer3 = new ObserverDelegate.BonusObserver(subject); //添加订阅 subject.Update += observer1.MakeCouponAsync; subject.Update += observer2.SendMessageAsync; subject.Update += observer3.AddBonusAsync; //发布通知 subject.State = "星巴克10十元券采购成功"; await subject.Notify(); Console.WriteLine("\n\nHappy Ending~"); Console.ReadLine(); } } }
展现结果和上面同样。
源码地址:https://gitee.com/sayook/DesignMode/tree/master/Observer