一、概述
观察者模式是一种常用的设计模式,它属于行为型模式。在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