设计模式--观察者模式
定义:
定义了对象之间一对多的关系,这样一来,当一个对象发生变化时,他的所有依赖者都会收到通知,并自动更新.
关键词:
observer : 观察者
subject : 主题
concreteObserver: 具体观察者
结构图:
应用场景:
当一个对象的状态变化时,需要通知其他多个对象进行同步更新时,可以使用此模式(如果有且只有一个对象需要更新,就没有必要了)
当需要动态增加删除需要同步的对象时
对象仅仅需要将自己的更新通知其他对象,而无需知道其他对象实现细节时.
优点:
subject 和 observer是高内聚,低耦合的,他们仅通过接口进行联系
无需指定具体的observer
缺点:
松耦合导致代码之间看起来关系不明显,比较难理解.
例子:
日志记录.当发生一个事件或者有状态变化时,需要日志记录下来.要求同时有数据库记录和文件记录.该如何写的?
通常写法是:
public class Record { public void notify() { DatabaseLog d = new DatabaseLog(); d.RecordToDataBase(); FileLog f = new FileLog(); f.RecordToFile(); } } public class DatabaseLog { public void RecordToDataBase() { //TODO } } public class FileLog { public void RecordToFile() { //TODO } }当有变化时,页面上只需要调用
Record r = new Record(); r.notify();
即可.
但是:如果要求新增一种记录方式,web记录时,该如何处理呢?
新增一个WebLog类,然后修改Record类.
public class Record { public void notify() { DatabaseLog d = new DatabaseLog(); d.RecordToDataBase(); FileLog f = new FileLog(); f.RecordToFile(); WebLog w = new WebLog(); w.RecordToWeb(); } } public class DatabaseLog { public void RecordToDataBase() { //TODO } } public class FileLog { public void RecordToFile() { //TODO } } public class WebLog { public void RecordToWeb() { //TODO } }于是,我们发现:针对实际编程,每当有新增时,我们都需要添加新的记录类,并且修改Record类.仔细观察三种记录方式,其实都是在对所发生的事情那个做记录,只是记录的方式不一样罢了.
类图:
代码:
public interface ISubject { void RegisterObserver(IObserver observer); void RemoveObserver(IObserver observer); void NotifyObservers(); } public class Record : ISubject { private ArrayList observersList; public Record() { observersList = new ArrayList(); } public void RegisterObserver(IObserver observer) { observersList.Add(observer); } public void RemoveObserver(IObserver observer) { observersList.Remove(observer); } public void NotifyObservers() { foreach (IObserver observer in observersList) { observer.Record(); } } public void SetEvent(int el) { if (el > 10) { NotifyObservers(); } } } public interface IObserver { void Record(); } public class DatabaseLog : IObserver { private ISubject subject; public DatabaseLog(ISubject subject) { this.subject = subject; subject.RegisterObserver(this); } public void Record() { //TODO } } public class FileLog : IObserver { private ISubject subject; public FileLog(ISubject subject) { this.subject = subject; subject.RegisterObserver(this); } public void Record() { //TODO } } public class WebLog : IObserver { private ISubject subject; public WebLog(ISubject subject) { this.subject = subject; subject.RegisterObserver(this); } public void Record() { //TODO } }
页面调用:
protected void Page_Load(object sender, EventArgs e) { Record r = new Record(); DatabaseLog dbl = new DatabaseLog(r); FileLog fl = new FileLog(r); WebLog wl = new WebLog(r); r.SetEvent(100); }此时,如果需要增加其他的记录方式的话,需要添加一个类实现Iobserver,然后还需要修改客户端页面.通过配置文件,我们还可以使客户端做到易插拔.
<hr/>
以下来自<<深入浅出设计模式>>
涉及到的设计原则:
封装变化在观察者模式中,会改变的是主题(Subject)的状态,以及观察者(Observer)的数量和具体类型.面向接口编程观察者和主题都使用接口,观察者使用主题的接口,主题使用观察者的接口.做到了松耦合.优先使用对象组合,而不是继承观察者模式利用组合讲许多观察者组合进主题,对象之间的这种关系不是通过继承得到的,而是在运行时运用动态的组合生成的.