观察者模式

观察者模式(Observer):在对象间定义一种一对多的依赖关系,以便当某对象的状态改变时,与它存在依赖关系的所有对象都能收到通知并自动进行更新。

  • MVC模式的底层可以说就是利用了观察者模式

基础设计

我们可以使用如下的方式设计一个简单的观察者模式,在被观察者中需要存储一个观察者组,提供一个发送消息的方法对观察组进行消息推送。

在观察者中提供一个消息响应的方法,响应消息。

事件
1
2
3
4
5
6
7
8
/// <summary>
/// 事件
/// </summary>
public enum Event
{
捡到金币,
通关
}
接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/// <summary>
/// 观察者接口
/// </summary>
public interface IObserver
{
/// <summary>
/// 接收通知
/// </summary>
/// <param name="subject"></param>
/// <param name="eventMsg"></param>
void OnNotify(Subject subject, Event eventMsg);
}

/// <summary>
/// 被观察者接口
/// </summary>
public interface ISubject
{
List<IObserver> Observers();
void AddObserver(IObserver observer);
void RemoveObserver(IObserver observer);
}
实体对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/// <summary>
/// 观察者
/// </summary>
public class Observer : IObserver
{
public void OnNotify(Subject subject, Event eventMsg)
{
switch (eventMsg)
{
case Event.捡到金币:
subject.Score += 10;
break;
case Event.通关:
subject.Score += 100;
break;
}
}
}

/// <summary>
/// 被观察者
/// </summary>
public class Subject : ISubject
{
public int Score;
private readonly List<IObserver> _observers;

/// <summary>
/// 发送消息
/// </summary>
/// <param name="eventMsg"></param>
public void Notify(Event eventMsg)
{
_observers.ForEach(x=>x.OnNotify(this,eventMsg));
}

public Subject()
{
_observers = new List<IObserver>();
}

public List<IObserver> Observers()
{
return _observers;
}

public void AddObserver(IObserver observer)
{
_observers.Add(observer);
}

public void RemoveObserver(IObserver observer)
{
_observers.Remove(observer);
}
}

使用委托和事件

在Csharp中内置了委托和事件来处理这种一对多的响应方式。

c#内置了委托和事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
using System;

namespace ObserverPattern
{
/// <summary>
/// 观察者模式
/// </summary>
internal static class Program
{

public static void Main(string[] args)
{
var c = new Cat() {Name = "小白"};
var m = new Mouse(c) {Name = "小鼠"};
c.OnCatCom();

}
}

class Cat
{
public string Name { get; set; }
public event Action catCom;
public virtual void OnCatCom()
{
Console.WriteLine("{0}来了",Name);
catCom?.Invoke();
}
}

class Mouse
{
public string Name { get; set; }
public Mouse(Cat cat)
{
//将事件绑定到方法
cat.catCom += this.MouseRun;
}
private void MouseRun()
{
Console.WriteLine("{0}快跑!!",Name);
}
}
}

思考

其实观察者模式就是对象的一种间接同步调用,使用这种方法是为了解除耦合,达到统一分配管理的作用。

从上文提到的可以知道,这种模式是同步的,也就是说当存在一组观察者时,那么可能会导致阻塞,但在实际中可能没这么严重,但在使用中我们还需注意。

如果你在每次响应后给出一个状态,表示通知的响应情况,那么这就接近 责任链模式了。

销毁对象?

在书中提到一个问题很有趣,在观察者模式中销毁对象该怎么办呢?

在销毁对象前,需要解除监听,确保对象被正确销毁。

现状

观察者模式出现于1994年(比我还大:smile:),因此基本都是基于类来实现的,但现在更流行函数式编程,可能不太符合现在的编程美学。例如C#的event就是现代化的观察者模式。