观察者模式
观察者模式定义了一种一对多的依赖关系,让多个观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。
问题:一般系统都将一个系统分割成一些列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来大大的不便。
观察者模式的优点:观察者模式是依赖倒转原则的最佳体现,它所做的工作其实就是在接触耦合。让耦合的双方都依赖与抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。观察者模式的关键对象是抽象通知者和抽象观察者,一个抽象通知者可以有任意数目的依赖它的抽象观察者,一旦通知者的状态发生变化,所有的观察者都可一得到通知。而通知者发出通知时,并不需要知道谁是它的观察者,而任何一个具体观察者不知道也不需要知道其他的观察者存在。
应用:当一个对象的改变需要同时改变其他对象,而且它不知道具体有多少个对象有待改变的时候,要考虑应用观察者模式;一个抽象模型有两个方面,其中一方面依赖于另一方面,这时观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。
改进:我们还可以对观察者模式进行改进,我们可以将抽象类换成接口。具体的观察者完全有可能是风马牛不相及的类,但他们都需要根据通知者的通知来做出Update()的操作。
下面看一下观察者模式:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program {//客户端 static void Main(string[] args) { ConcreteSubject s = new ConcreteSubject(); s.Attach(new ConcreteObserver(s, "x")); s.Attach(new ConcreteObserver(s, "y")); s.Attach(new ConcreteObserver(s, "z")); s.SubjectState = "ABC"; s.Notify(); Console.Read(); } } //抽象通知者 abstract class Subject { private IList<Observer> observers = new List<Observer>(); //增加观察者 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(); } } } // 抽象观察者 abstract class Observer { public abstract void Update(); } //具体观察者 class ConcreteSubject : Subject { private string subjectState; //具体被观察者状态 public string SubjectState { get { return subjectState; } set { subjectState = value; } } } //具体观察者 class ConcreteObserver : Observer { private string name; private string observerState; private ConcreteSubject subject; public ConcreteObserver(ConcreteSubject subject, string name) { this.subject = subject; this.name = name; } public override void Update() { observerState = subject.SubjectState; Console.WriteLine("观察者{0}的新状态是{1}", name, observerState); } public ConcreteSubject Subject { get { return subject; } set { subject = value; } } } }
观察者模式也有不足,为了达到通知者与观察者之间根部就互相不知道,由客户端决定同志谁的目的,我们通过委托改进观察者模式:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace 老板来了 { class Program { static void Main(string[] args) { Boss huhansan = new Boss(); Secretary misu = new Secretary(); //看股票的同事 StockObserver tongshi1 =new StockObserver("围观宅",huhansan ); //看NBA的同事 NBAObserver tongshi2 = new NBAObserver("以观察",huhansan ); misu.Update += new EventHandler(tongshi1.CloseStockMarket); misu.Update += new EventHandler(tongshi2.CloseNBADirectSeeding ); huhansan.Update += new EventHandler(tongshi1.CloseStockMarket ); huhansan.Update +=new EventHandler(tongshi2.CloseNBADirectSeeding ); //老板回来了,改变SubjectState的状态 huhansan.SubjectState = "我胡汉三回来了!"; //发出通知 huhansan.Notify(); misu.Notify(); Console.Read(); } } //看股票的同事 class StockObserver { private string name; private Subject sub; public StockObserver(string name, Subject sub) { this.name = name; this.sub = sub; } //关闭股市行情 public void CloseStockMarket() { Console.WriteLine("{0} {1} 关闭股票行情,继续工作! ",sub.SubjectState ,name); } } //看NBA的同事 class NBAObserver { private string name; private Subject sub; public NBAObserver(string name, Subject sub) { this.name = name; this.sub = sub; } //关闭NBA直播 public void CloseNBADirectSeeding() { Console.WriteLine("{0} {1} 关闭NBA直播,继续工作!",sub.SubjectState ,name); } } //通知者接口 interface Subject { void Notify(); string SubjectState { get; set; } } //声明一个委托,名称叫做“EventHandler”(事件处理程序),无参数,无返回值 delegate void EventHandler(); //老板类 class Boss : Subject { //声明一个事件Update,类型为委托EventHandler public event EventHandler Update; private string action; public void Notify() { //在访问“通知”方法时,调用“更新” Update(); } public string SubjectState { get { return action; } set { action = value; } } } //秘书类 class Secretary : Subject { public event EventHandler Update; private string action; public void Notify() { //在访问“通知”方法时,调用“更新” Update(); } public string SubjectState { get { return action; } set { action = value; } } } }
关于委托的详细用法,待续。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构