设计模式观察者模式(Observer)
讲故事(user story)
假设我们是一个优惠券提供平台,故事就发生在顾客在我们平台采购完成支付成功后。
支付完成后平台要进行的一些操作:
短信通知客户已经生成订单
增加顾客的积分
开始按订单需求制券
。。。(可能会有许多操作)
接下来就是将故事以代码的形式展现出来。。。
需求分析
我们将上述故事转化为代码中的对象分别是: 支付成功 PaySuccessSubject、短信通知 MessageObserver、积分增加 BonusObserver、制券 CouponObserver。
当支付成功PaySuccessSubject后,要通知到MessageObserver,BonusObserver,CouponObserver这三个对象,为了实现上面这个需求,将采用观察者模式(发布-订阅)
敲黑板.划重点
观察者模式又叫发布-订阅(Publish/Subscribe)模式,定义了一种一对多的依赖关系,让多个观察者对象同时 监听某一个主题对象。当主题对象在状态发生变化时,通知所有观察者对象,使他们能够自己更新自己。
Show Code
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("
Happy Ending~");
Console.ReadLine();
}
结果显示
Code Upgrade
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("
Happy 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("
Happy Ending~");
Console.ReadLine();
}
}
}
展示结果和上面一样。
源码地址:https://gitee.com/sayook/DesignMode
以上是 设计模式观察者模式(Observer) 的全部内容, 来源链接: utcz.com/z/533264.html