观察者模式
观察者模式又叫做发布-订阅(Publish/Subscribe)模式。
1、Subject类,可翻译为主题或者抽象通知者,一般用一个抽象类或者一个接口实现。它把所有对观察者对象的引用保存在一个集合里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
import java.util.ArrayList;
import java.util.List;
/**
* @Description: Subject类,可翻译为主题或者抽象通知者,一般用一个抽象类或者一个接口实现。它把所有对观察者对象的引用保存在一个集合里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
* @author: zxt
* @time: 2019年4月25日 上午10:54:34
*/
public class Subject {
private List<Observer> observers = new ArrayList<Observer>();
// 增加观察者
public void attach(Observer observer) {
observers.add(observer);
}
// 移除观察者
public void detach(Observer observer) {
observers.remove(observer);
}
// 通知
public void notifyUpdate() {
for(Observer o : observers) {
o.update();
}
}
}
2、抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者一般用一个抽象类或者一个接口实现。更新接口通常包含一个update()方法,这个方法叫做更新方法。
/**
* @Description: 抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者一般用一个抽象类或者一个接口实现。更新接口通常包含一个update()方法,这个方法叫做更新方法
* @author: zxt
* @time: 2019年4月25日 上午11:01:12
*/
public abstract class Observer {
public abstract void update();
}
3、ConcreteSubject类,叫做具体主题或者具体通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。
/**
* @Description: ConcreteSubject类,叫做具体主题或者具体通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。
* @author: zxt
* @time: 2019年4月25日 上午11:09:24
*/
public class ConcreteSubject extends Subject {
// 具体被观察者状态
private String subjectState;
public String getSubjectState() {
return subjectState;
}
public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
}
}
4、ConcreteObserver类,具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。具体观察者可以保存一个指向具体主题对象的引用。
/**
* @Description: ConcreteObserver类,具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。具体观察者角色可以保存一个指向具体主题对象的引用。
* @author: zxt
* @time: 2019年4月25日 上午11:22:18
*/
public class ConcreteObserver extends Observer {
private String name;
private String observerState;
private ConcreteSubject subject;
public ConcreteObserver(ConcreteSubject subject, String name) {
this.name = name;
this.subject = subject;
}
@Override
public void update() {
observerState = subject.getSubjectState();
System.out.println("观察者 " + name + " 的新状态是" + observerState);
}
public ConcreteSubject getSubject() {
return subject;
}
public void setSubject(ConcreteSubject subject) {
this.subject = subject;
}
}
观察者模式的特点
将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维护一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。
而观察者模式的关键对象是主题Subject和观察者Observer,一个Subject可以有任意数目的依赖它的Observer,一旦Subject的状态发生了改变,所有的Observer都可以得到通知。Subject发出通知时并不需要知道谁是它的观察者,也就是说,具体观察者是谁,它根本不需要知道。而任何一个具体观测者不知道也不需要知道其他观察者的存在。
当一个对象的改变需要同时改变其他对象的时候,而且它不知道具体有多少对象有待改变时,应该使用观察者模式。一个抽象模型有两个方面,其中一方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。总的来说,观察者模式所做的工作其实就是在解除耦合,让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不会影响另一边的变化。
而在具体的应用中观察者完全可能是风马牛不相及的类,但它们都需要根据通知者的通知来做出Updata()的操作,所以抽象观察者为接口比类更好。
public interface Observer {
public abstract void update();
}
观察者模式的不足
1、观察者所要做的状态更新不一定都在Updata()方法中,有可能是其他方法(或者说没有抽象观察者这样的接口呢),通知者状态改变时如何做到通知不同类的不同方法做出改变。
2、通知者对所有的观测者的通知需要循环依次唤醒。
3、解决上述问题的方法:事件委托机制。委托就是一种引用方法的类型。一旦为委托分配了方法,委托与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看做是对函数的抽象,是函数的“类”,委托的实例将代表一个具体的函数。而且一个委托可以搭载多个方法,所有方法被一次唤醒。更重要的是,它可以使得委托对象所搭载的方法并不需要同属于一个类。
委托机制使得抽象主题类中的增加和减少的抽象观察者集合以及通知时遍历的抽象观察者都不必要了。转到客户端来让委托搭载多个方法,这也就解决了本来与抽象观察者的耦合问题。
网友评论