摘要
本文以C#示例说明观察者模式的概念和应用场景。
定义
观察者模式(Observer Pattern <[əb'zɝvɚ] ['pætɚn]>, 有时又被称为发布&订阅(Publish&Subscribe)模式)是软件设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实时事件处理系统。维基百科
解读
- 关键词:发布-订阅
- 应用场景:猎头招聘,日志系统,新用户注册
- 被观察者知道观察者的存在,并能调用观察者提供的接口,比如求职者和猎头之间的关系;
- 目的:解决观察者和信息发布者之间的耦合问题。
现实生活中的场景
- 微信朋友圈
- ...
下面用代码示例进行说明:
场景
日志消息的记录和打印,产生的字符串类型的日志消息分别在控制台/屏幕打印和记录文本/磁盘文件。
具体实现如下
using System;
using System.IO;
public interface ILogObserver
{
int id { get; set; }
void Insert(string message);
}
public class LogSubject
{
// 观察者队列
private List<ILogObserver> observers;
public LogSubject()
{
observers = new List<ILogObserver>();
}
// 观察者注册
public void Register(ILogObserver obs)
{
if (!observers.Exists(ob=>ob.id==obs.id)
{
observers.add(obs);
}
}
// 观察者移除
public void Remove(ILogObserver obs)
{
if (observers.Exists(ob=>ob.id==obs.id)
{
observers.Remove(obs);
}
}
// 调用观察者接口
public void Notify(string message)
{
foreach (ILogObserver obs in observers)
{
obs.Insert(message);
}
}
}
/// <summary>控制台日志</summary>
public class ConsoleLog: ILogObserver
{
public int id { get; set; }
public void Insert(string message)
{
System.Console.WriteLine(message);
}
}
/// <summary>文本日志</summary>
public class TextLog: ILogObserver
{
public int id { get; set; }
public void Insert(string message)
{
string filePath = "x:\log.txt";
System.File.AppendLine(filePath, message);
}
}
使用事件实现
在 .Net 中,可以利用事件和委托简化观察者模式的实现,上面的例子可以修改如下:
// 定义委托
public delegate void LogInsertedEventHandler<LogInsertEventArgs>(string message);
// 被观察者
public class LogInserter
{
public LogInsertedEventHandler<LogInsertEventArgs> LogInserted;
public void AddObserver(LogInsertedEventHandler<LogInsertEventArgs> handler)
{
LogInserted += handler;
}
public void RemoveObserver(LogInsertedEventHandler<LogInsertEventArgs> handler)
{
LogInserted -= handler;
}
public void Insert(string message) => LogInserted?.Invoke(message);
}
// 委托/事件参数
public class LogInsertEventArgs : EventArgs
{
public string Message { get; set; }
public LogInsertEventArgs(string message)
{
this.Message = message;
}
}
// 订阅者接口
public interface ILogSubscriber
{
void LogInserted(string message);
}
// 订阅者实现(控制台打印)
public class ConsoleLogSubscriber : ILogSubscriber
{
public void LogInserted(string message)
{
Console.WriteLine($"日志打印到屏幕: {message}");
}
}
// 订阅者实现(追加到文本)
public class TextLogSubscriber : ILogSubscriber
{
public void LogInserted(string message)
{
Console.WriteLine($"日志追加到文本: {message}");
}
}
// 调用
class Program
{
static void Main(string[] args)
{
// 被观察者
LogInserter ins = new LogInserter();
// 观察者定义
TextLogSubscriber textSub = new TextLogSubscriber();
ConsoleLogSubscriber consoleSub = new ConsoleLogSubscriber();
// 添加观察者
ins.AddObserver(handler: new LogInsertedEventHandler<LogInsertEventArgs>(textSub.LogInserted));
ins.AddObserver(handler: new LogInsertedEventHandler<LogInsertEventArgs>(consoleSub.LogInserted));
// 产生日志
ins.Insert("这是日志内容");
Console.ReadLine();
}
}
输出如下:
日志追加到文本: 这是日志内容
日志打印到屏幕: 这是日志内容
好了,今天的观察者模式就总结到这里,大家继续回去写BUG吧