观察者模式
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
如何解决:使用面向对象技术,可以将这种依赖关系弱化。
关键代码:在抽象类里有一个 ArrayList 存放观察者们。
应用实例: 1、拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价。 2、西游记里面悟空请求菩萨降服红孩儿,菩萨洒了一地水招来一个老乌龟,这个乌龟就是观察者,他观察菩萨洒水这个动作。
优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。
缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
使用场景:
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
- 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
- 一个对象必须通知其他对象,而并不知道这些对象是谁。
- 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
注意事项: 1、JAVA 中已经有了对观察者模式的支持类。 2、避免循环引用。 3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。
实例UML图:
实例代码:
/**
* @author Shuyu.Wang
* @package:com.shuyu.publish
* @description:抽象关系者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫更新接口;
* 抽象观察者一般用一个抽象类或者一个接口实现,更新接口通常包含一个update方法,这个方法叫更新方法。
* @date 2018-11-20 23:01
**/
public interface Observer {
void update();
}
/**
* @author Shuyu.Wang
* @package:com.shuyu.publish
* @description:具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调;
* @date 2018-11-20 23:19
**/
@Slf4j
public class ConcreteObserver implements Observer {
private String name;
private String observerState;
private ConcreteSubject concreteSubject;
public ConcreteObserver(ConcreteSubject concreteSubject,String name) {
this.concreteSubject=concreteSubject;
this.name=name;
}
@Override
public void update() {
observerState=concreteSubject.getSubjectState();
log.info("观察者的新状态是:"+name+" "+observerState);
}
public ConcreteSubject getConcreteSubject() {
return concreteSubject;
}
public void setConcreteSubject(ConcreteSubject concreteSubject) {
this.concreteSubject = concreteSubject;
}
}
/**
* @author Shuyu.Wang
* @package:com.shuyu.publish
* @description:主题或抽象通知者,一般用一个抽象类或者一个接口实现,它把所有对观察者的对象的引用
* 保存在一个聚集里,每个主题都可以有任何数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象
* @date 2018-11-20 22:57
**/
public class SubjectPub {
private List<Observer> observers=new ArrayList<>();
/**
* @author:shuyu.wang
* @description:增加观察者
* @date: 2018/11/20 23:05
* @param null :
* @return : null
*/
public void attach(Observer observer){
observers.add(observer);
}
/**
* @author:shuyu.wang
* @description:移除观察者
* @date: 2018/11/20 23:06
* @param null :
* @return : null
*/
public void detach(Observer observer){
observers.remove(observer);
}
/**
* @author:shuyu.wang
* @description:通知
* @date: 2018/11/20 23:07
* @param null :
* @return : null
*/
public void notifyA(){
for (Observer o : observers) {
o.update();
}
}
}
/**
* @author Shuyu.Wang
* @package:com.shuyu.publish
* @description:具体主题或具体通知者,将有关状态存入具体观察者对象,在具体主题的内部状态改变时,
* 给所有登记过的观察者发出通知
* @date 2018-11-20 23:14
**/
@Data
public class ConcreteSubject extends SubjectPub{
private String subjectState;
}
测试代码:
@RunWith(SpringRunner.class)
@SpringBootTest
public class PublishApplicationTests {
@Test
public void contextLoads() {
ConcreteSubject subject=new ConcreteSubject();
subject.attach(new ConcreteObserver(subject,"X"));
subject.attach(new ConcreteObserver(subject,"Y"));
subject.attach(new ConcreteObserver(subject,"Z"));
subject.setSubjectState("ABC");
subject.notifyA();
}
}
运行结果:
2018-11-20 23:33:29.738 INFO 17908 —- [ main] com.shuyu.PublishApplicationTests : Started PublishApplicationTests in 3.895 seconds (JVM running for 5.227)
2018-11-20 23:33:29.956 INFO 17908 —- [ main] com.shuyu.publish.ConcreteObserver : 观察者的新状态是:X ABC
2018-11-20 23:33:29.956 INFO 17908 —- [ main] com.shuyu.publish.ConcreteObserver : 观察者的新状态是:Y ABC
2018-11-20 23:33:29.956 INFO 17908 —- [ main] com.shuyu.publish.ConcreteObserver : 观察者的新状态是:Z ABC
还没有评论,来说两句吧...