定义
观察者模式又称为发布/订阅模式,是一种对象的行为型模式。它定义了对象之间的一对多的依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象都得到通知并被自动更新。
就类似于Spring MVC模式的事件,消息机制,javaScript的事件监听等等。
如何衍生该模式?
按照常规的代码思维来说, 一个对象产生业务变化,对应的其他与之相关联的对象也需要修改,那么代码实现方面就是如下:
public interface ConcreteObserver {
void update();
}
public class ObserverA implements ConcreteObserver {
@Override
public void update() {
System.out.println("皇上,臣妾给您做桂花糕吃!!!");
}
}
public class ObserverB implements ConcreteObserver{
@Override
public void update() {
System.out.println("皇上,臣妾给您做鱼籽燕窝吃!!!");
}
}
public class ObserverC implements ConcreteObserver{
@Override
public void update() {
System.out.println("皇上,老娘给你做满汉全席!!!");
}
}
/**
* 观察者测试类
* @author zzg
*
*/
public class ObserverTest {
@Test
public void notifyTest() {
// 发出一个消息
System.out.println("来人啊,给朕来十个包子");
// 通知到各个观察者
ConcreteObserver observerA = new ObserverA();
ConcreteObserver observerB = new ObserverB();
ConcreteObserver observerC = new ObserverC();
observerA.update();
observerB.update();
observerC.update();
}
}
来人啊,给朕来十个包子
皇上,臣妾给您做桂花糕吃!!!
皇上,臣妾给您做鱼籽燕窝吃!!!
皇上,老娘给你做满汉全席!!!
仔细观察的话,还是我娘对我好! 不好意思偏题了。 一看代码就知道发现问题了,
1、我一个被观察者对象(皇上)要主动通知观察者(嫔妃们);
2、如果增加一个观察者(招妃子)就要修改代码,移除(废妃子)是不是还要修改代码;
3、后宫佳丽三千,皇上有点屁事会一个一个通知嘛?肯定是嫔妃一个个主动打听获取啦;
4、皇上还要知道你的回应(调用),傻,肯定嫔妃主动做出摆出姿势啦(回应)。
所以,理应该如此:Java对象方面,一个对象产生修改而其他对象也需要修改,但是对象本体是不知道有哪些对象需要修改的;
对象本体也应该是不用知道观察者对象而通知到对象(观察者们 )。
代码分析图解:
从角色区分:
主题(Subject):主题接口类,规定了我们需要的方法:添加、删除观察者以及通知观察者更新数据的方法。
具体主题(ConcreteSubject):是实现主题接口类的一个实现类,大概会存储观察者们的实时数据
观察者(Observer):该接口用来通知具体观察者,并让观察者做出响应,更新数据的方法。
具体观察者(ConcreteObserver):是实现观察者接口类的一个实现类,可以注册主题或让这个具体主题将自己从具体主题的集合中删除,使自己不再是它的观察者。
举个栗子
某个知名明星(被观察者)
/**
* 主题接口类
* @author zzg
*
*/
public interface ObserverSubject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObserver(String message);
}
public class ObserverImpl implements ObserverSubject{
private List<Observer> list;
public ObserverImpl() {
list = new ArrayList<Observer>();
}
public ObserverImpl(List<Observer> list) {
this.list = list;
}
@Override
public void registerObserver(Observer observer) {
list.add(observer);
}
@Override
public void removeObserver(Observer observer) {
list.remove(observer);
}
@Override
public void notifyObserver(String message) {
if(null != list && list.size() > 0 ) {
for (Observer observer : list) {
observer.update(message);
}
}
}
public void sendInfo(String message) {
System.out.println("------------消息已发布-----------");
notifyObserver(message);
}
}
/**
* 观察者接口
* @author zzg
*
*/
public interface Observer {
void update(String message);
void receiveMessage();
}
public class FansObserver implements Observer{
private String fansName;
// 业务消息
private String message;
@Override
public void update(String message) {
// 更新数据
this.message = message;
}
@Override
public void receiveMessage() {
System.out.println(fansName +" 获取到消息: " + message);
}
public FansObserver(String fansName) {
this.fansName = fansName;
}
public String getFansName() {
return fansName;
}
public void setFansName(String fansName) {
this.fansName = fansName;
}
}
public static void main(String[] args) {
ObserverImpl subject = new ObserverImpl();
for (int i = 0; i < 5; i++) {
Observer observer = new FansObserver(i + "号粉丝");
// 注册一个观察者
subject.registerObserver(observer);
subject.sendInfo("点餐开始");
observer.receiveMessage();
observer.update("点餐完成");
observer.receiveMessage();
}
for (int i = 0; i < 5; i++) {
Observer observer = new FansObserver(i + "号粉丝");
// 移除一个观察者
subject.removeObserver(observer);
}
}
运行结果:
1号粉丝 获取到消息: 点餐开始
1号粉丝 获取到消息: 点餐完成
------------消息已发布-----------
2号粉丝 获取到消息: 点餐开始
2号粉丝 获取到消息: 点餐完成
------------消息已发布-----------
3号粉丝 获取到消息: 点餐开始
3号粉丝 获取到消息: 点餐完成
------------消息已发布-----------
4号粉丝 获取到消息: 点餐开始
4号粉丝 获取到消息: 点餐完成
优点方面:
1、观察者模式满足“开闭原则”,
2、观察者和被观察者是抽象耦合的。
3、它实现了表示层和数据层的分离,并定义了稳定的更新消息传递机制,类别清晰,抽象了更新接口,使得相同的数据层可以有各种不同的表示层。