5

初识设计模式 - 观察者模式 - 程序员翔仔

 1 year ago
source link: https://www.cnblogs.com/fatedeity/p/16797903.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

初识设计模式 - 观察者模式

观察者设计模式(Observer Design Pattern)的别名有很多,如发布 - 订阅(Publish/Subscribe)模式、模型 - 视图(Model/View)模式、源 - 监听(Source/Listener)模式或从属者(Dependents)模式。

无论是何种名称,其意图都是在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。

其主要解决了一个对象状态改变之后给其他对象通知的问题,而且考虑到易用性和低耦合,保证高度的协作性。

在发布 - 订阅模式当中,观察者就是订阅者,一般是需要定义一个抽象的观察者接口,其代码示例如下:

public interface Observer { void update(); }

具体的观察者类也很简单,只需要简单实现接口即可,其代码示例如下:

public class ConcreteObserver implements Observer { // 实现响应方法 public void update() { // 具体响应代码 }}

定义完订阅者,其次就是发布者,通常是将之定义为一个抽象的目标类,其代码示例如下:

public abstract class Subject { // 定义一个观察者集合存储所有观察者对象 protected List<Observer> observers = new ArrayList<>(); // 注册方法,用于向观察者集合增加一个观察者 public void attach(Observer observer) { observers.add(observer); } // 注销方法,用于向观察者集合删除一个观察者 public void detach(Observer observer) { observers.remove(observer); } // 声明抽象的通知方法,需要由子类具体实现 abstract void notifyObservers();}

根据不同的场景定义不一样的具体目标类,如下是一种代码示例:

public class ConcreteSubject extends Subject { // 实现具体的通知方法 @Override public void notifyObservers() { // 遍历观察者集合,调用每一个观察者的响应方法 for (Observer ob : observers) { ob.update(); } }}

观察者模式的主要优点如下:

  • 观察者模式可以实现表示层和数据逻辑层的分离
  • 观察者模式在观察目标和观察者之间建立了一个抽象的耦合
  • 观察者模式支持广播通信,简化了一对多系统设计的难度
  • 增加新的具体观察者无需修改原有代码,符合开闭原则

观察者模式的主要缺点如下:

  • 如果目标对象的观察者有很多,将所有的观察者都通知到会非常耗时
  • 如果目标对象和观察者存在循环依赖,观察目标会触发它们之间进行循环调用,最终导致系统崩溃

观察者模式的适用场景如下:

  • 将具有依赖关系的两种抽象模型独立出来,使它们可以独立地改变和复用
  • 一个对象的改变将导致一个或多个其他对象也发生改变,但并不知道具体有多少对象将发生改变,也不知道这些对象是谁
  • 可以使用观察者模式创建一种链式触发机制

在 JDK 的 java.util 包中,提供了 Observer 接口和 Observable 类,它们构成了 JDK 对观察者模式的支持。

如下是 Observer 接口的源码:

@Deprecated(since = "9")public interface Observer { void update(Observable o, Object arg);}

如下是 Observable 类的部分源码:

@Deprecated(since = "9")public class Observable { private boolean changed = false; private Vector<Observer> obs; public Observable() { obs = new Vector<>(); } // 注册观察者,线程安全 public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); // 注册时去重 if (!obs.contains(o)) { obs.addElement(o); } } // 注销观察者,线程安全 public synchronized void deleteObserver(Observer o) { obs.removeElement(o); } // 通知观察者,无参数模式 public void notifyObservers() { notifyObservers(null); } // 通知观察者,带参数模式 public void notifyObservers(Object arg) { // 保存观察者的状态,备忘录模式的简单应用 Object[] arrLocal; // 获取观察者时候锁住 synchronized (this) { if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } // 逐一调用观察者的处理方法 for (int i = arrLocal.length - 1; i >= 0; i--) ((Observer) arrLocal[i]).update(this, arg); } public synchronized void deleteObservers() { obs.removeAllElements(); } protected synchronized void setChanged() { changed = true; } protected synchronized void clearChanged() { changed = false; } public synchronized boolean hasChanged() { return changed; } public synchronized int countObservers() { return obs.size(); }}

需要注意的是,在 JDK 9 之后已经不推荐使用 Observer 接口和 Observable 类。


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK