观察者模式(ObserverPattern):定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
观察者模式结构:
Observer:Observer类,抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己;
Subject:他把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象;
ConcreteSubject:具体主题,将有关状态存入具体观察者对象,在具体主题的内部状态改变时,给所有登记过的观察者发出通知
ConcreteObserver:具体观察类,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。
本篇文章按照书中的顺序来逐步解释,所以内容会比较多。主要是代码演示的逐步修改占据大量内容。但希望你能跟着思路。另外说明本文使用的是Java来实现。
1、版本1.0:初步演示效果:
(1)新建一个类,作用相当于信使:
package secretaryobserver; import lombok.Getter; import lombok.Setter; import staffobserver.StockObserver; import java.util.ArrayList; import java.util.List; /** * Created by Administrator on 2017/8/6. */ public class Secretary { //同事列表 private List<StockObserver> observers = new ArrayList<StockObserver>(); @Getter @Setter private String actionWhy; @Getter @Setter private String actionResult; //添加通知对象 public void attach(StockObserver observer){ observers.add(observer); } public void notifyStock(){ for (StockObserver observer : observers) { observer.update(); } } public void secretaryAction(String staffName){ System.out.println(getActionWhy() +","+ staffName +"," + getActionResult()); } }
(2)新建一个类,作用相当于信使的服务对象:
package staffobserver; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import secretaryobserver.Secretary; /** * Created by Administrator on 2017/8/6. */ @AllArgsConstructor @NoArgsConstructor public class StockObserver { private String name; private Secretary secretary; public void update(){ secretary.secretaryAction(name); } }
(3)测试类:
import org.junit.Test; import secretaryobserver.Secretary; import staffobserver.StockObserver; /** * Created by Administrator on 2017/8/6. */ public class TestObserver { @Test public void testObserver(){ Secretary secretary = new Secretary(); StockObserver stockObserver1 = new StockObserver("Tom",secretary); StockObserver stockObserver2 = new StockObserver("Jerry",secretary); secretary.attach(stockObserver1); secretary.attach(stockObserver2); secretary.setActionWhy("今天不开会了"); secretary.setActionResult("你回去吧。"); secretary.notifyStock(); } }
执行结果如下
不过这个版本很大的缺陷就是代码相互耦合,显然背离我们的设计原则。
2、代码修改,进行解耦操作,版本2.0
(1)增加抽象的观察者类:
package abstractobserver; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import secretaryobserver.Secretary; /** * Created by Administrator on 2017/8/6. */ @AllArgsConstructor @Getter @Setter public abstract class Observer { private String name; private Secretary secretary; public abstract void update(); }
(2)将原来的StockObserver继承这个抽象类,
package concreteobserver; import abstractobserver.Observer; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import secretaryobserver.Secretary; /** * Created by Administrator on 2017/8/6. */ public class StockObserver extends Observer{ public StockObserver(String name, Secretary secretary) { super(name, secretary); } public void update(){ super.getSecretary().secretaryAction(super.getName()); } }
(3)修改信使类:
package secretaryobserver; import abstractobserver.Observer; import lombok.Getter; import lombok.Setter; import java.util.ArrayList; import java.util.List; /** * Created by Administrator on 2017/8/6. */ public class Secretary { //同事列表 private List<Observer> observers = new ArrayList<Observer>(); @Getter @Setter private String actionWhy; @Getter @Setter private String actionResult; //添加通知对象,且参数定义为父类类型 public void attach(Observer observer){ observers.add(observer); } //隔离通知对象,且参数定义为父类类型 public void detach(Observer observer){ observers.remove(observer); } public void notifyStock(){ for (Observer observer : observers) { observer.update(); } } public void secretaryAction(String staffName){ System.out.println(getActionWhy() +","+ staffName +"," + getActionResult()); } }
(4)测试类也做一些稍微修改:
import abstractobserver.Observer; import concreteobserver.StockObserver; import org.junit.Test; import secretaryobserver.Secretary; /** * Created by Administrator on 2017/8/6. */ public class TestObserver { @Test public void testObserver(){ Secretary MissWang = new Secretary(); Observer stockObserver1 = new StockObserver("Tom",MissWang); Observer stockObserver2 = new StockObserver("Jerry",MissWang); MissWang.attach(stockObserver1); MissWang.attach(stockObserver2); MissWang.setActionWhy("今天不开会了"); MissWang.setActionResult("你回去吧。"); MissWang.notifyStock(); } }
执行结果同上。
3、代码修改,进一步的解耦操作,版本3.0
(1)增加抽象信使的接口:
package abstractsecretary; import abstractobserver.Observer; /** * Created by Administrator on 2017/8/6. */ //信使接口 public interface SubjectInform { void attach(Observer observer); void detach(Observer observer); void notifyStock(); void secretaryAction(String str); }
(2)修改具体信使类,继承信使接口,这样做的目的是当有多个信使时,比较方便。
package secretaryobserver; import abstractobserver.Observer; import abstractsecretary.SubjectInform; import lombok.Getter; import lombok.Setter; import java.util.ArrayList; import java.util.List; /** * Created by Administrator on 2017/8/6. */ public class Secretary implements SubjectInform{ //同事列表 private List<Observer> observers = new ArrayList<Observer>(); @Getter @Setter private String actionWhy; @Getter @Setter private String actionResult; //添加通知对象,且参数定义为父类类型 public void attach(Observer observer){ observers.add(observer); } //隔离通知对象,且参数定义为父类类型 public void detach(Observer observer){ observers.remove(observer); } public void notifyStock(){ for (Observer observer : observers) { observer.update(); } } public void secretaryAction(String staffName){ System.out.println(getActionWhy() +","+ staffName +"," + getActionResult()); } }
(3)其他的类值是将原来具体的参数引用类型修改为实现接口之后的接口类型即可。
(4)为了测试隔离通知方法,我们在测试类中添加这个方法试试:
import abstractobserver.Observer; import concreteobserver.StockObserver; import org.junit.Test; import secretaryobserver.Secretary; /** * Created by Administrator on 2017/8/6. */ public class TestObserver { @Test public void testObserver(){ Secretary MissWang = new Secretary(); Observer stockObserver1 = new StockObserver("Tom",MissWang); Observer stockObserver2 = new StockObserver("Jerry",MissWang); MissWang.attach(stockObserver1); MissWang.attach(stockObserver2); //隔离通知 stockObserver1 MissWang.detach(stockObserver1); MissWang.setActionWhy("今天不开会了"); MissWang.setActionResult("你回去吧。"); MissWang.notifyStock(); } }
执行结果如下:可以看到效果没问题。
观察者模式特点:
问题描述:将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象见的一致性,我们不希望为了维持一致性而使类之间紧密耦合,这样会给维护和重用带来很大的不变。
而观察者模式的关键对象时主题Subject和观察者Observer,一个Subject可以有多个依赖它的Observer,一旦Subject的状态发生变化,所有的Observer都可以得到通知,Subject发出通知时并不需要知道它的观察者是谁,也就是说,具体观察者是谁他根本不知道,而任何一个具体观察者不知道也不需要知道其他观察者的存在。
应用场合:当一个对象 的改变需要同时改变其他对象的时候,并且在它不知道具体有多少对象有待改变时就该考虑使用观察者模式;还有当一个抽象模型有两个方面,其中一个方面依赖于另一面这是用观察者模式可以将这两者封装在独立的对象中使他们各自独立的改变和复用。
总的来说,观察者模式所做的工作其实就是在解除耦合,让耦合的双方都依赖于抽象,而不是依赖于具体,从而是的各自变化都不会影响另一边的变化。
嗯,以上就是观察者模式的介绍,到此基本结束了。