观察者模式——Java实例
一、定义
观察者模式(有时又被称为模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
二、结构
一个软件系统常常要求在某一个对象的状态发生变化的时候,某些其他的对象做出相应的改变。做到这一点的设计方案有很多,但是为了使系统能够易于复用,应该选择低耦合度的设计方案。减少对象之间的耦合有利于系统的复用,但是同时设计师需要使这些低耦合度的对象之间能够维持行动的协调一致,保证高度的协作。观察者模式是满足这一要求的各种设计方案中最重要的一种。
观察者模式结构中通常包括观察目标和观察者两个继承层次结构,其结构如图所示:
观察者模式所涉及的角色有:
- 抽象主题(Subject)角色:抽象主题角色把所有对观察者对象的引用保存在一个聚集(比如ArrayList对象)里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,抽象主题角色又叫做抽象被观察者(Observable)角色。
- 具体主题(ConcreteSubject)角色:将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者(Concrete Observable)角色。
- 抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口。
- 具体观察者(ConcreteObserver)角色:存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态 像协调。如果需要,具体观察者角色可以保持一个指向具体主题对象的引用。
三、示例代码
参考GitHub中的事例 https://github.com/qiaojiuyuan/ObserverPattern/tree/master/src ,给出观察者模式类图如下所示:
抽象主题角色类
1 public interface Observable {
2 /**
3 * 增加一个观察者
4 * @param observable
5 */
6 public void addObserver(Observer observable);
7 /**
8 * 删除一个观察者
9 * @param observable
10 */
11 public void deleteObserver(Observer observable);
12 /**
13 * 通知观察者
14 * @param context
15 */
16 public void notifyObserviers(String context);
17 }
被观察者活动
1 public interface IHanFeiZi {
2 /**
3 * 韩非子吃饭
4 */
5 public void haveBreakfast();
6 /**
7 * 韩非子娱乐
8 */
9 public void haveFun();
10 }
具体主题角色类
1 public class HanFeiZi implements Observable,IHanFeiZi{
2 private ArrayList<Observer> observableList = new ArrayList<>();
3
4 @Override
5 public void addObserver(Observer observable) {
6 this.observableList.add(observable);
7 }
8
9 @Override
10 public void deleteObserver(Observer observable) {
11 this.observableList.remove(observable);
12 }
13
14 @Override
15 public void notifyObserviers(String context) {
16 for(Observer observer : observableList) {
17 observer.update(context);
18 }
19 }
20
21 @Override
22 public void haveBreakfast() {
23 System.out.println("韩非子:开始吃饭");
24 this.notifyObserviers("韩非子在吃饭");
25 }
26
27 @Override
28 public void haveFun() {
29 System.out.println("韩非子:开始娱乐");
30 this.notifyObserviers("韩非子在娱乐");
31 }
32 }
抽象观察者角色类
1 public interface Observer {
2 public void update(String context);
3 }
具体观察者角色类
1 public class LiSi implements Observer{
2 @Override
3 public void update(String context) {
4 System.out.println("李斯:观察到韩非子活动,开始向老板汇报");
5 this.reportToQinShihuang(context);
6 }
7
8 private void reportToQinShihuang(String reportcontent) {
9 System.out.println("报告,韩非子有活动:"+reportcontent);
10 }
11 }
1 public class WangSi implements Observer{
2 private final static String TAG = WangSi.class.getSimpleName();
3
4 @Override
5 public void update(String context) {
6 // TODO Auto-generated method stub
7 System.out.println(TAG+"观察到韩非子有变化");
8 report(context);
9 }
10
11 private void report(String context) {
12 System.out.println("报告韩非子的状态:"+context);
13 }
14 }
客户端类
1 public class ClientMain {
2 public static void main(String[] args) {
3 Observer lisi = new LiSi();
4 Observer wangsi = new WangSi();
5 HanFeiZi hanFeiZi = new HanFeiZi();
6 hanFeiZi.addObserver(lisi);
7 hanFeiZi.addObserver(wangsi);
8 hanFeiZi.haveBreakfast();
9 hanFeiZi.haveFun();
10 }
11 }
四、特性
1.优点
(1) 观察者模式可以实现表示层和数据逻辑层的分离,定义了稳定的消息更新传递机制,并抽象了更新接口,使得可以有各种各样不同的表示层充当具体观察者角色;
(2) 观察者模式在观察目标和观察者之间建立一个抽象的耦合。观察目标只需要维持一个抽象观察者的集合,无须了解其具体观察者。由于观察目标和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次;
(3) 观察者模式支持广播通信,观察目标会向所有已注册的观察者对象发送通知,简化了一对多系统设计的难度;
(4) 观察者模式满足“开闭原则”的要求,增加新的具体观察者无须修改原有系统代码,在具体观察者与观察目标之间不存在关联关系的情况下,增加新的观察目标也很方便。
2.缺点
(1) 如果一个观察目标对象有很多直接和间接观察者,将所有的观察者都通知到会花费很多时间;
(2) 如果在观察者和观察目标之间存在循环依赖,观察目标会触发它们之间进行循环调用,可能导致系统崩溃;
(3) 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
3.适用场景
(1) 一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两个方面封装在独立的对象中使它们可以各自独立地改变和复用;
(2) 一个对象的改变将导致一个或多个其他对象也发生改变,而并不知道具体有多少对象将发生改变,也不知道这些对象是谁;
(3) 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
五、参考博客
https://www.cnblogs.com/renhui/p/6479748.html
https://www.cnblogs.com/java-my-life/archive/2012/05/16/2502279.html