观察者模式(Observer Pattern)
观察者模式
一、什么是观察者模式?
观察者模式(别名--发布-订阅)是软件设计模式的一种。观察者模式属于行为型模式。(行为型模型-特别关注对象之间的通信)
观察者模式(Observer)完美的将观察者和被观察的对象分离开。观察者设计模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动更新。
易用和低耦合,保证高度的协作。
二、观察者模式的适用场景
- 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。
- 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变。
- 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之,你不希望这些对象是紧密耦合的。
三、观察者模式的具体实现
结构图
![](https://blog-static.cnblogs.com/files/zt19994/observer.gif)
观察者模式中的四个重要角色
- 抽象被观察者角色(Observable):即一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个添加和删除观察者角色的接口。一般用一个抽象类和接口来实现。
- 抽象观察者角色(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
- 具体被观察者角色(ConcreteObservable):也就是一个具体的主题,当具体主题的内部状态改变时,给所有登记过的观察者发出通知。
- 具体观察者角色(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以使其自身状态和主题的状态保持一致。
java代码实现
1.定义一个抽象被观察者接口,添加、删除、通知观察者
package com.designpattern.observerPattern;
/**
* 被观察者接口 Observable
*
* @author zhongtao on 2018/9/10
*/
public interface Observable {
/**
* 添加观察者
*/
void addObserver(Observer observer);
/**
* 移除观察者
*/
void removeObserver(Observer observer);
/**
* 通知观察者
*/
void notifyObserver();
}
2.定义一个抽象观察者接口
package com.designpattern.observerPattern;
/**
* 观察者接口 Observer
*
* @author zhongtao on 2018/9/10
*/
public interface Observer {
/**
* 更新消息
*/
void update(String message);
}
3.实现被观察者,有一个List集合,用以保存注册的观察者,等需要通知观察者时,遍历该集合。
package com.designpattern.observerPattern;
import java.util.ArrayList;
import java.util.List;
/**
* 具体被观察者
*
* @author zhongtao on 2018/9/10
*/
public class ConcreteObservable implements Observable {
// 用来存储观察者对象的集合
private List<Observer> list = new ArrayList<Observer>();
//消息
private String message;
@Override
public void addObserver(Observer observer) {
list.add(observer);
}
@Override
public void removeObserver(Observer observer) {
if(!list.isEmpty()) {
list.remove(observer);
}
}
@Override
public void notifyObserver() {
for (Observer observer : list) {
observer.update(message);
}
}
/**
* 设置更新消息
* @param message
*/
public void setNotifyMessage(String message){
this.message = message;
System.out.println("更新消息:" + message);
notifyObserver();
}
}
4.实现观察者
package com.designpattern.observerPattern;
/**
* 具体实现观察者
*
* @author zhongtao on 2018/9/10
*/
public class User implements Observer {
private String name;
public User(String name){
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + "你有新消息了:" + message);
}
}
5.测试观察者模式
package com.designpattern.observerPattern;
import org.junit.Test;
/**
* 观察者模式测试类
*
* @author zhongtao on 2018/9/10
*/
public class ObserverPatternTest {
/**
* 测试观察者模式
*/
@Test
public void testObserverPattern() {
ConcreteObservable observable = new ConcreteObservable();
User peter = new User("Peter");
User make = new User("Make");
User lina = new User("Lina");
//添加观察者
observable.addObserver(peter);
observable.addObserver(make);
observable.addObserver(lina);
observable.setNotifyMessage("星际争霸2中人族太IMBA");
System.out.println("-----分割线-----");
observable.removeObserver(peter);
observable.setNotifyMessage("星灵才是最IMBA的!");
}
}
测试结果:当移除peter之后,peter就无法再收到推送消息了。
更新消息:星际争霸2中人族太IMBA
Peter你有新消息了:星际争霸2中人族太IMBA
Make你有新消息了:星际争霸2中人族太IMBA
Lina你有新消息了:星际争霸2中人族太IMBA
-----分割线-----
更新消息:星灵才是最IMBA的!
Make你有新消息了:星灵才是最IMBA的!
Lina你有新消息了:星灵才是最IMBA的!
四、观察者模式的优缺点
优点:
- 观察者和被观察者是抽象耦合的。
- 建立一套触发机制。
缺点:
- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
- 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
- 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。