观察者模式(Observer)
定义
定义对象间的一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
结构说明
- Subject:目标对象,通常居有如下功能
- 一个目标可以被多个观察者观察
- 目标提供对观察者注册和退订的维护
- 当目标的状态发生变化时,目标负责通知所有注册的、有效的观察者
- Observer:定义观察者的接口,提供目标通知时对应的更新方法,这个更新方法进行相应的业务处理,可以再这个方法里面返回调用目标对象,以获取目标对象的数据
- ConcreteSubject:具体的目标实现对象,用来维护目标状态,当目标对象的状态发生改变时,通知所有注册的、有效的观察者,让观察者执行相应的处理。
- ConcreteObserver:观察者的具体实现对象,用来接收目标的通知,并进行相应的后续处理,比如更新自身的状态以保持和目标的相应状态一致。
示例代码
/// <summary>
/// 目标对象,它知道观察它的观察者,并提供注册和删除观察者的接口
/// </summary>
public class Subject
{
//用老保存注册的观察者对象
private List<Observer> observers=new List<Observer>();
/// <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>
protected void NotifyObservers()
{
foreach (var observer in observers)
{
observer.Update(this);
}
}
}
/// <summary>
/// 具体的目标对象,负责把有关状态存入到相应的观察者对象
/// 并在自己状态发生改变时,通知各个观察者
/// </summary>
public class ConcreteSubject : Subject
{
//示意,目标对象的状态
private string subjectState;
public string GetSubjectState()
{
return subjectState;
}
public void SetSubjectState(string subjectState)
{
this.subjectState = subjectState;
//状态发生了改变,通知各个观察者
this.NotifyObservers();
}
}
/// <summary>
/// 观察者接口,定义一个更新的接口给那些再目标发生改变的时候被通知的对象
/// </summary>
public interface Observer
{
/// <summary>
/// 更新的接口
/// </summary>
/// <param name="subject">传入目标对象,方便获取相应的目标对象的状态</param>
void Update(Subject subject);
}
/// <summary>
/// 具体观察者对象,实现更新的方法,是自身的状态和目标的状态保持一致
/// </summary>
public class ConcreteObserver : Observer
{
//示例,观察者的状态
private string observerStats;
public void Update(Subject subject)
{
//具体的更新实现
//这里可能需要更新观察者的状态,使其与目标的状态保持一致
observerStats = ((ConcreteSubject) subject).GetSubjectState();
}
}
实现示例
/*
* 报纸订阅示例
*/
public class Subject
{
//用来保存注册的观察者对象,也就是报纸的订阅者
private List<Observer> readers = new List<Observer>();
/// <summary>
/// 报纸的读者需要向报社订阅,先要注册
/// </summary>
/// <param name="reader">报纸的读者</param>
public void Attach(Observer reader)
{
readers.Add(reader);
}
/// <summary>
/// 报纸的读者可以取消订阅
/// </summary>
/// <param name="reader"></param>
public void Detach(Observer reader)
{
readers.Remove(reader);
}
/// <summary>
/// 当每期报纸印刷出来后,就是迅速主动的被推送到读者的手中
/// 相当于通知读者,让他们知道
/// </summary>
protected void NotifyObservers()
{
foreach (var observer in readers)
{
observer.Update(this);
}
}
}
/// <summary>
/// 报纸对象,具体的目标实现
/// </summary>
public class NewsPaper : Subject
{
//报纸的具体内容
private string _content;
/// <summary>
/// 获取报纸的具体内容
/// </summary>
/// <returns></returns>
public string GetContent()
{
return _content;
}
/// <summary>
/// 示意,设置报纸的具体内容,相当于要出版报纸了
/// </summary>
/// <param name="content"></param>
public void SetContent(string content)
{
_content = content;
//内容有了,说明又出报纸了,那就通知所有读者
NotifyObservers();
}
}
/// <summary>
/// 观察者,比如报纸的阅读者
/// </summary>
public interface Observer
{
/// <summary>
/// 被通知的方法
/// </summary>
/// <param name="subject">具体的目标对象,可以获取报纸的内容</param>
void Update(Subject subject);
}
/// <summary>
/// 真正的读者,为了简单就描述一下姓名
/// </summary>
public class Reader : Observer
{
//读者姓名
public string Name { get; set; }
public void Update(Subject subject)
{
//这是采用拉的方式
Console.WriteLine($"{Name}收到报纸了,阅读它。内容是==={((NewsPaper)subject).GetContent()}");
Console.ReadKey();
}
}
观察者模式的本质:触发联动
当修改目标对象的时候,就会触发相应的通知,然后会循环调用所有注册的观察者对象的相应方法,其实就相当于联动调用这些观察者的方法。
而且这个联动还是动态的,可以通过注册和取消注册来控制观察者,因而可以在程序运行期间,通过动态的控制观察者,来变相的实现添加和删除某些功能处理,这些功能就是观察者再update的时候执行的功能。
同时目标对象和观察者对象的解耦,又保证了无论观察者发生怎样的变化,目标对象总是能够正确的联动过来。
理解这个本质对我们非常有用,对于我们识别和使用观察者模式有非常重要的意义,尤其是在变形使用的时候。万变不离其宗。
本文作者:huihui_teresa
本文链接:https://www.cnblogs.com/huiteresa/p/17700325.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步