一、认识观察者模式
观察者模式定义:属于对象行为模式,当多个对象之间存在一对多的依赖关系,即一个对象的状态发生改变时,所以依赖它的对象都会得到通知并被自动更新。这种模式有时又被称为发布-订阅模式、模型-视图模式。
结构:
抽象主题角色(Subject):即抽象类,提供了添加、移除观察者的方法,以及一个通知所有观察者的抽象方法。
具体主题角色(Concrete Subject):也称为具体目标类,实现抽象目标中的通知方法,一旦该类内部发生了什么改变时,通知所有注册过的观察者对象。
抽象观察者(Observer):是一个抽象类或接口,包含了一个更新自己的抽象方法,当接到具体主题的更改时被调用。
具体观察者(Concrete Observer):实现抽象观察者中的更新方法,一旦目标角色发出更新通知时会调用该更新方法来更新自身的状态。
优缺点:
优点:降低了目标与观察者之间的耦合关系,符合依赖倒置原则,开闭原则。目标与观察者之间建立了一套触发机制。
缺点:目标与观察者之间依赖关系并没有完全解除,可能出现循环引用。并且若是当在主题角色中的观察者过多时,通知发布会花费很多时间,影响程序的效率。
实际应用场景:
JDK中的java.util.Observable。
Spring中的org.springframework.context.ApplicationListener。
二、实现观察者模式
实现过程
demo见xyz.changlu.observer包下代码:
抽象观察者(接口):Observer
public interface Observer { void response(); }
抽象主题类:Subject
public abstract class Subject { protected List<Observer> observers = new ArrayList<>(); //添加观察者到集合中 public void addObserver(Observer observer){ observers.add(observer); } //移除指定观察者 public void removeObserver(Observer observer){ observers.remove(observer); } //具体通知方法让实现类去实现 public abstract void notifyAllObserver(); }
具体观察者:Task1、Task2
//具体观察者1号 public class Task1 implements Observer { @Override public void response() { System.out.println("Task1收到通知,正在执行任务2....."); } } //具体观察者2号 public class Task2 implements Observer { @Override public void response() { System.out.println("Task2收到通知,正在执行任务2....."); } }
具体主题者:ConcreteSubject
public class ConcreteSubject extends Subject { @Override public void notifyAllObserver() { System.out.println("收到通知"); //开始通知到所有的观察者 for (Observer observer : observers) { observer.response(); } } }
测试程序:测试类Customer
public class Customer { public static void main(String[] args) { //创建两个任务 Task1 task1 = new Task1(); Task2 task2 = new Task2(); //创建主题角色,并添加两个观察者(及任务) ConcreteSubject subject = new ConcreteSubject(); subject.addObserver(task1); subject.addObserver(task2); //进行更新通知 subject.notifyAllObserver(); } }
首先将多个任务(即观察者)添加到主题类中(存放在一个list集合里),一旦ConcreteSubject主题类进行了更新操作,即可调用其实现Subject抽象类的实现方法notifyAllObserver()来通知观察者集合中的各个观察者执行任务。
说明:解决的是当一个对象进行更新或其他操作时对应要去更改执行或通知多个任务时,我们即可以使用观察者模式。
实际应用情况描述
问题描述
若是主题进行了更新,并且该更新涉及到了需要个部分,此时你会怎么呢?若是没有了解过观察者模式的也许会这样:
class Weather{ //执行更新操作 public void update(){ dao.update();//本方法核心的更新操作 //通知的操作 Task task = new Task(); Task2 task2 = new Task2(); task.doThing1(); task2.doThing2(); } } class Task{ void doThing1(){ ... } } class Task2{ void doThing2(){ .... } }
你可能会在update()操作中去new多个对象并且逐一执行,若是某一天要少通知一个单位的话还需要去手动删除…
解决对策
创建一个抽象类,其包含了一个集合专门用来存放多个观察者对象,并包含添加、移除操作:
//抽象主题 public abstract class Subject { protected List<Observer> observers = new ArrayList<>(); //添加观察者到集合中 public void addObserver(Observer observer){ observers.add(observer); } //移除指定观察者 public void removeObserver(Observer observer){ observers.remove(observer); } public abstract void notifyAllObserver(); }
再创建一个抽象观察者接口,其带有一个通知方法:
public interface Observer { void response(); }
万事具备了,我们开始改造原来的两个类:
class Weather extends Subject{ //执行更新操作 public void update(){ dao.update();//本方法核心的更新操作 //调用通知操作即可!!! notifyAllObserver(); } //实现一个通知方法 @Override public void notifyAllObserver() { //通知所有的观察者开始执行其自己的操作 for (Observer observer : observers) { observer.response(); } } } //两个任务分别实现了观察者接口 class Task implements Observer{ void doThing1(){ ... } @Override public void response() { doThing1();//不仅仅可以添加该方法,还可以添加其他方法 } } class Task2{ void doThing2(){ .... } @Override public void response() { doThing2();//不仅仅可以添加该方法,还可以添加其他方法 } }
测试使用时:
public class Customer { public static void main(String[] args) { Weather weather = new Weather(); //添加指定的任务 weather.addObserver(new Task()); weather.addObserver(new Task2()); //执行其中的更新操作 weather.update();//此时调用更新操作时,自动会执行集合中的所有观察者操作 } }
感悟:在对观察者模式进行思考时,将模式应用到实际案例中去,去通过使用设计模式来去解决整个项目的架构问题,提高方法解耦!!!
总结
1、对于观察者模式,在出现一对多的关系操作时可以进行使用来实现方法解耦,一般应当是当要执行更新或其他操作影响到很多个对象时,为了方便管理通知可以使用到该模式。
2、优点是符合开闭原则、依赖倒置原则,对于目标与观察者之间建立了连接。缺点是依赖关系没有完全解除,若是观察者过多通知发布会耗费很多时间,影响程序的效率。