版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34359363/article/details/82378116
什么是观察者模式?
观察者模式也叫发布订阅模式,顾名思义就是定义对象间一对多的关系,当一个对象的状态发生改变的时候,所以依赖于他的对象都能得到通知并被自动更新。
观察者模式的要素
- 抽象目标角色(被观察者) 目标角色知道它的观察者,可以有任意多个观察者同时来观察一个目标,并且提供注册和删除观察者对象的接口。目标角色往往由抽象类或者接口实现
- 抽象观察者角色 为那些在目标发生改变时需要获取得通知的对象定义一个更新的接口。抽象观察者角色主要由抽象类和接口实现。
- 具体目标角色(被观察者的具体实现) 将有关状态存入各个具体观察角色对象,当他状态发生改变时,向他的各个观察者发出通知。
- 具体观察者角色 储存有关状态,这些状态应与目标的状态保持一致。实现观察者角色的更新接口以使自身状态和目标状态保持一致,在这个角色内部也可以维护一个只想具体目标角色对象的引用。
简单例子
package myDesignPatternsTest.observerPattern;
/**
* 抽象目标角色
*/
public interface Observable {
//增加一个观察者
public void addObserver(Observer observer);
//删除一个观察者
public void deleteObserver(Observer observer);
//通知观察者 发什么了什么
public void notifyObservers(String context);
}
package myDesignPatternsTest.observerPattern;
/**
* 抽象观察者类
*/
public interface Observer {
//一发现别人有动静,自己也要行动起来
public void update(String context);
}
package myDesignPatternsTest.observerPattern;
import java.util.ArrayList;
/**
* 具体目标类
*/
public class zhangdachui implements Observable {
//定义一个list 将所有的观察者放进去
private ArrayList<Observer> list =new ArrayList<Observer>();
@Override
public void addObserver(Observer observer) {
this.list.add(observer);
}
@Override
public void deleteObserver(Observer observer) {
this.list.remove(observer);
}
@Override
public void notifyObservers(String context) {
//通知每个观察者我干什么了
for (Observer observer : list) {
observer.update(context);
}
}
public void haveBreakfast(){
System.out.println("张大锤准备吃饭");
this.notifyObservers("张大锤要吃饭了");
}
public void toSleep(){
System.out.println("张大锤要午睡了");
this.notifyObservers("张大锤马上要午睡了");
}
}
package myDesignPatternsTest.observerPattern;
import java.util.Date;
/**
* 具体观察者
*/
public class toukuikuag1 implements Observer {
@Override
public void update(String context) {
System.out.println("偷窥狂一号:张大锤现在在干什么呢?好像知道啊");
lodingText(context);
}
public static void lodingText(String news){
System.out.println("偷窥狂一号:小本本记录上:"+new Date()+":"+news);
}
}
package myDesignPatternsTest.observerPattern;
import java.util.Date;
/**
* 具体观察者
*/
public class toukuikuag2 implements Observer {
@Override
public void update(String context) {
System.out.println("偷窥狂二号:张大锤现在在干什么呢?好像知道啊");
lodingText(context);
}
public static void lodingText(String news){
System.out.println("偷窥狂二号:小本本记录上:"+new Date()+":"+news);
}
}
package myDesignPatternsTest.observerPattern;
import java.util.Date;
/**
* 具体观察者
*/
public class toukuikuag3 implements Observer {
@Override
public void update(String context) {
System.out.println("偷窥狂三号:张大锤现在在干什么呢?好像知道啊");
lodingText(context);
}
public static void lodingText(String news){
System.out.println("偷窥狂三号:小本本记录上:"+new Date()+":"+news);
}
}
package myDesignPatternsTest.observerPattern;
public class Client {
public static void main(String[] args) {
zhangdachui zdc=new zhangdachui();
zdc.addObserver(new toukuikuag1());
zdc.addObserver(new toukuikuag2());
zdc.addObserver(new toukuikuag3());
zdc.haveBreakfast();
zdc.toSleep();
}
}
张大锤准备吃饭
偷窥狂一号:张大锤现在在干什么呢?好像知道啊
偷窥狂一号:小本本记录上:Tue Sep 04 13:36:10 CST 2018:张大锤要吃饭了
偷窥狂二号:张大锤现在在干什么呢?好像知道啊
偷窥狂二号:小本本记录上:Tue Sep 04 13:36:10 CST 2018:张大锤要吃饭了
偷窥狂三号:张大锤现在在干什么呢?好像知道啊
偷窥狂三号:小本本记录上:Tue Sep 04 13:36:10 CST 2018:张大锤要吃饭了
张大锤要午睡了
偷窥狂一号:张大锤现在在干什么呢?好像知道啊
偷窥狂一号:小本本记录上:Tue Sep 04 13:36:10 CST 2018:张大锤马上要午睡了
偷窥狂二号:张大锤现在在干什么呢?好像知道啊
偷窥狂二号:小本本记录上:Tue Sep 04 13:36:10 CST 2018:张大锤马上要午睡了
偷窥狂三号:张大锤现在在干什么呢?好像知道啊
偷窥狂三号:小本本记录上:Tue Sep 04 13:36:10 CST 2018:张大锤马上要午睡了
Process finished with exit code 0
在我们使用observer类和observable的时候在进行导入的时候我们发现java.util也提供了这两个包,那我们就用java自带的这两包来实现上面的例子
package myDesignPatternsTest.observerPattern;
import java.util.ArrayList;
import java.util.Observable;
/**
* 具体目标类 继承的是java自带的Observable
*/
public class zhangdachui extends Observable {
/* private ArrayList<Observer> list =new ArrayList<Observer>();
public void addObserver(Observer observer) {
this.list.add(observer);
}
public void deleteObserver(Observer observer) {
this.list.remove(observer);
}
public void notifyObservers(String context) {
//通知每个观察者我干什么了
for (Observer observer : list) {
observer.update(context);
}
}*/
public void haveBreakfast(){
System.out.println("张大锤准备吃饭");
//这是一个发布功能
super.setChanged();
super.notifyObservers("张大锤要吃饭了");
}
public void toSleep(){
System.out.println("张大锤要午睡了");
super.setChanged();
super.notifyObservers("张大锤马上要午睡了");
}
}
package myDesignPatternsTest.observerPattern;
import java.util.Date;
import java.util.Observable;
import java.util.Observer;
/**
* 具体观察者
*/
public class toukuikuag1 implements Observer {
/* public void update(String context) {
System.out.println("偷窥狂一号:张大锤现在在干什么呢?好像知道啊");
lodingText(context);
}*/
@Override
public void update(Observable o, Object arg) {
System.out.println("偷窥狂一号:张大锤现在在干什么呢?好像知道啊");
lodingText(arg.toString());
}
public static void lodingText(String news){
System.out.println("偷窥狂一号:小本本记录上:"+new Date()+":"+news);
}
}
package myDesignPatternsTest.observerPattern;
public class Client {
public static void main(String[] args) {
zhangdachui zdc=new zhangdachui();
zdc.addObserver(new toukuikuag1());
zdc.addObserver(new toukuikuag2());
zdc.addObserver(new toukuikuag3());
zdc.haveBreakfast();
zdc.toSleep();
}
}
//结果没有任何变化
张大锤准备吃饭
偷窥狂三号:张大锤现在在干什么呢?好像知道啊
偷窥狂三号:小本本记录上:Tue Sep 04 14:08:03 CST 2018:张大锤要吃饭了
偷窥狂二号:张大锤现在在干什么呢?好像知道啊
偷窥狂二号:小本本记录上:Tue Sep 04 14:08:03 CST 2018:张大锤要吃饭了
偷窥狂一号:张大锤现在在干什么呢?好像知道啊
偷窥狂一号:小本本记录上:Tue Sep 04 14:08:03 CST 2018:张大锤要吃饭了
张大锤要午睡了
偷窥狂三号:张大锤现在在干什么呢?好像知道啊
偷窥狂三号:小本本记录上:Tue Sep 04 14:08:03 CST 2018:张大锤马上要午睡了
偷窥狂二号:张大锤现在在干什么呢?好像知道啊
偷窥狂二号:小本本记录上:Tue Sep 04 14:08:03 CST 2018:张大锤马上要午睡了
偷窥狂一号:张大锤现在在干什么呢?好像知道啊
偷窥狂一号:小本本记录上:Tue Sep 04 14:08:03 CST 2018:张大锤马上要午睡了
观察者模式的优缺点
优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。
缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
观察者模式的适用场景
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
- 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
- 一个对象必须通知其他对象,而并不知道这些对象是谁。
- 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
使用观察者模式要注意什么
1、JAVA 中已经有了对观察者模式的支持类。 2、避免循环引用。 3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。