一、概述
观察者模式是一种常用的设计模式,它属于行为型模式。在C#中,观察者模式通过定义一种一对多的依赖关系,使得当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。这种模式可以实现松耦合,使得被观察者和观察者之间的关系更加灵活。
在C#中实现观察者模式通常需要以下几个角色:
1. Subject(主题):被观察者,它维护了一个观察者列表,并提供了添加、删除和通知观察者的方法。
2. Observer(观察者):观察者,它定义了一个更新方法,用于接收被观察者发出的通知。
3. ConcreteSubject(具体主题):具体的被观察者,它继承或实现了主题接口,并实现了具体的业务逻辑。它会在自身状态发生变化时通知观察者。
4. ConcreteObserver(具体观察者):具体的观察者,它继承或实现了观察者接口,并实现了更新方法。当接收到被观察者的通知时,它会执行相应的逻辑。
通过使用观察者模式,我们可以实现对象之间的解耦,使得它们之间的依赖关系更加灵活和可扩展。这种模式在事件处理、GUI开发以及许多其他场景中都有广泛应用。
观察者模式的优点和缺点:
观察者模式的优点:
1. 松耦合:被观察者和观察者之间的关系是松耦合的,它们可以独立变化而互不影响。
2. 可扩展性:可以方便地增加新的观察者,或者在不影响现有代码的情况下增加新的被观察者。
3. 易于维护:观察者模式将业务逻辑分散到各个观察者中,使得代码更加清晰、易于维护。
4. 支持广播通信:被观察者可以同时通知多个观察者,实现广播式的通信。
观察者模式的缺点:
1. 观察者过多时的性能问题:如果观察者过多或者观察者的更新操作比较耗时,可能会影响系统的性能。
2. 循环依赖问题:观察者和被观察者之间存在循环依赖的情况下,可能导致系统出现问题。
3. 更新顺序不确定:观察者模式中,观察者的更新顺序是不确定的,可能会导致一些意外的结果。
观察者模式适用于以下场景:
1. 当一个对象的状态变化需要通知其他多个对象,并且这些对象的行为需要根据该状态变化做出相应的调整时,可以使用观察者模式。
2. 当一个对象需要在不知道有多少个其他对象关注它的情况下,动态地将消息通知给这些对象时,可以使用观察者模式。
3. 当一个对象的改变需要同时影响其他多个对象,并且它不希望与这些对象形成紧耦合关系时,可以使用观察者模式。
4. 当系统中的某个对象需要与其他多个对象进行解耦,以降低对象之间的依赖性时,可以使用观察者模式。
5. 当需要实现事件驱动的系统或者消息通知机制时,可以使用观察者模式。
观察者模式适用于多个对象之间存在一对多的依赖关系,当一个对象的状态发生变化时,需要通知其他多个对象进行相应的处理。它能够实现对象之间的解耦,提高系统的灵活性和可扩展性。
二、代码实现
新建一个控制台项目
代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace 观察者模式
{internal class Program{static void Main(string[] args){ConcreteSubject subject = new ConcreteSubject();ConcreteObserver observer1 = new ConcreteObserver("Observer 1", subject);ConcreteObserver observer2 = new ConcreteObserver("Observer 2", subject);ConcreteObserver observer3 = new ConcreteObserver("Observer 3", subject);subject.AddObserver(observer1);subject.AddObserver(observer2);subject.AddObserver(observer3);subject.State = 1; // 触发通知subject.RemoveObserver(observer2);subject.State = 2; // 触发通知Console.ReadKey();}}// 主题接口public interface ISubject{void AddObserver(IObserver observer);void RemoveObserver(IObserver observer);void NotifyObservers();}// 具体主题public class ConcreteSubject : ISubject{private List<IObserver> observers = new List<IObserver>();private int state;public int State{get { return state; }set{state = value;NotifyObservers();}}public void AddObserver(IObserver observer){observers.Add(observer);}public void RemoveObserver(IObserver observer){observers.Remove(observer);}public void NotifyObservers(){foreach (IObserver observer in observers){observer.Update();}}}// 观察者接口public interface IObserver{void Update();}// 具体观察者public class ConcreteObserver : IObserver{private string name;private ConcreteSubject subject;public ConcreteObserver(string name, ConcreteSubject subject){this.name = name;this.subject = subject;}public void Update(){Console.WriteLine($"Observer {name} received an update. New state: {subject.State}");}}
}
运行:
三、解析代码
上面的代码看起来比较复杂,在23个设计模式中,其实还不算最复杂的,看多了习惯就好,下面大致的讲下代码逻辑。
首先是定义了一个接口 ISubject,它有三个方法,添加观察者,移除观察者,通告观察者。
然后 ConcreteSubject 继承了这个接口,这里重点在 state 这个属性这里:
public int State
{get { return state; }set{state = value;NotifyObservers();}
}
如果设置属性的值,就会调用 NotifyObservers 方法,这是个通知所有观察者的一个方法。
ConcreteObserver 存储了 name 和 具体观察者 ConcreteSubject 的实例(具体的主题),不过这里,只是用到了打印 subject.State ,并无其他作用。
Console.WriteLine($"Observer {name} received an update. New state: {subject.State}");
在 ConcreteSubject.AddObserver 方法的参数是一个 IObserver 接口,其实传递的就是 ConcreteObserver 实例,这里由于只需要调用 Update 方法,所以只用到了一个接口 IObserver,虽然保护了 ConcreteObserver 类的开放权限,但使的整个过程看起来更加复杂了。
从工作的角度来说,上面的很多写法并不是那么推荐,将简单的事情复杂化,是在自己在刁难自己,还可能会导致更多的 bug,可别忘了公司里还有项目经理,老板,他们可是一直在催你快点做,他们可不管你代码写的怎么样,他们根本就不懂代码。
在 Main 函数中,实例化了三个 ConcreteObserver 类,并传入了 name , 并添加到了 subject 中,这就是添加了三个观察者,以便后面用消息来通知他们
在设置 subject.State = 1 时,默认就调用了 NotifyObservers 方法,也就调用了三个观察者的 Update 方法,理解了,就会发现这些代码其实没有那么难。
四、案例
下面的代码来源博客 JiYF大男孩,写的很不错,拿来做个参考,链接在下面
https://www.cnblogs.com/JiYF/p/6896458.html
新建类 Blog
using System.Collections.Generic;/// <summary>
/// 订阅者接口
/// </summary>
public interface IObserver
{void Receive(Blog blog);
}/// <summary>
/// 订阅博客抽象类
/// </summary>
public abstract class Blog
{/// <summary> /// 保存订阅者列表 /// </summary> private List<IObserver> observers = new List<IObserver>();/// <summary> /// 博主名 /// </summary> public string BlogName { get; set; }/// <summary> /// 博客标题 /// </summary> public string BlogTitle { get; set; }/// <summary> /// 博客信息 /// </summary> public string BlogInfo { get; set; }/// <summary> /// 博客构造函数 /// </summary> /// <param name="blogTitle">博客标题</param> /// <param name="blogInfo">博客信息</param> public Blog(string name, string blogTitle, string blogInfo){this.BlogName = name;this.BlogTitle = blogTitle;this.BlogInfo = blogInfo;}/// <summary> /// 添加一个订阅者 /// </summary> /// <param name="observer">具体的订阅者对象</param> public void AddObserver(IObserver observer){if (observers.Contains(observer)){return;}observers.Add(observer);}/// <summary> /// 删除一个订阅者 /// </summary> /// <param name="observer">具体的订阅者对象</param> public void RemoveObserver(IObserver observer){if (observers.Contains(observer)){observers.Remove(observer);}}/// <summary> /// 发布博客通知 /// </summary> public void PublishBlog(){//遍历通知每一个订阅者 foreach (IObserver ob in observers){if (ob != null){// 调用继承当前接口的Receive方法 ob.Receive(this);}}}
}
新建类 JiYFBlog
namespace 设计模式_观察者模式
{/// <summary> /// 具体的订阅博客类 /// </summary> public class JiYFBlog : Blog{public JiYFBlog(string name, string blogTitile, string blogInfo): base(name, blogTitile, blogInfo){}}
}
新建类 Observer
using System;namespace 设计模式_观察者模式
{/// <summary> /// 具体的订阅者类 /// </summary> public class Observer : IObserver{/// <summary> /// 订阅者名字 /// </summary> private string m_Name;public string Name{get { return m_Name; }set { m_Name = value; }}/// <summary> /// 订阅者构造函数 /// </summary> /// <param name="name">订阅者名字</param> public Observer(string name){this.m_Name = name;}/// <summary> /// 订阅者接受函数 /// </summary> /// <param name="blog"></param> public void Receive(Blog blog){Console.WriteLine("订阅者:\"{0}\"观察到了:{1}发布的一篇博客,标题为:{2},内容为:{3}", Name, blog.BlogName, blog.BlogTitle, blog.BlogInfo);}}
}
调用方法
using System;namespace 设计模式_观察者模式
{internal class Program{static void Main(string[] args){Console.WriteLine("--全部订阅者--");// 创建一个 JiYF 的博客 // 多态的方式发布一条播客,但此时还没有订阅者 Blog jiyfBlog = new JiYFBlog("JiYF笨小孩", "丑小鸭", "丑小鸭的故事");// 创建订阅者 Observer obsZhangsan = new Observer("张三");Observer obsLiSi = new Observer("李四");Observer obsWangwu = new Observer("王五");// 添加到 JiYF 博客的订阅者 jiyfBlog.AddObserver(obsZhangsan);jiyfBlog.AddObserver(obsLiSi);jiyfBlog.AddObserver(obsWangwu);//通知订阅者 jiyfBlog.PublishBlog();Console.WriteLine();Console.WriteLine("--移除订阅者张三--");jiyfBlog.RemoveObserver(obsZhangsan);jiyfBlog.PublishBlog();Console.ReadLine();}}
}
运行:
end