每一个角色都对应这一个类,好比观察者模式,观察者对应着观察者类,被观察者对应着被观察者类。实际上,设计模式就是经过面向对象的特性,将这些角色解耦java
观察者模式本质上就是一种订阅 / 发布的模型,从逻辑上来讲就是一对多的依赖关系。什么意思呢?比如是一群守卫盯着一个囚犯,只要囚犯一有异动,守卫就必须立刻采起行动(也有多是更新状态,本质上也是一种行动),那么守卫就是观察者,囚犯就是被观察者设计模式
在一个系统中,实现这种一对多的并且之间有必定关联的逻辑的时候,因为须要保持他们之间的协同关系,因此最简便的方法是采用紧耦合,把这些对象绑定到一块儿。可是这样一来,一旦有扩展或者修改的时候,开发人员所面对的难度很是大,并且很容易形成Bug。那么观察者模式就解决了这么一个问题,在保持一系列观察者和被观察者对象协同工做的同时,把解耦了它们函数
抽象观察者角色类this
public interface Observer { // 更新接口 public void update(); }
具体观察者角色类设计
public class ConcreteObserver implements Observer { // 观察者的状态 private String observerState = "Initial"; // 观察者初始状态,会随着被观察者变化而变化 private String name; // 观察者名称,用于标记不一样观察者 private Subject concreteSubject; // 构造观察者,并传入被主题对象,以及标识该观察者名称 public ConcreteObserver(Subject concreteSubject, String name) { this.concreteSubject = concreteSubject; this.name = name; System.out.println("我是观察者" + name +", 个人状态是" + observerState); } // 观察者状态随主题主题改变 public void update() { observerState = concreteSubject.SubjectState; System.out.println("我是观察者" + name +", 个人状态是" + observerState); } }
抽象主题角色类code
import java.util.List; public abstract class Subject { // 用来保存注册的观察者对象 List<Observer> list = null; String SubjectState; // 注册观察者对象 public void attach(Observer observer){}; //删除观察者对象 public void detach(Observer observer){}; // 通知全部注册的观察者对象 public void nodifyObservers(String newState){}; }
具体主题角色类server
import java.util.ArrayList; import java.util.List; public class ConcreteSubject extends Subject { private List<Observer> list = new ArrayList<Observer>(); public String SubjectState; // 注册观察者对象 public void attach(Observer observer) { list.add(observer); System.out.println("Attached an observer"); } //删除观察者对象 public void detach(Observer observer){ list.remove(observer); } // 通知全部注册的观察者对象 public void nodifyObservers(String newState) { for(Observer observer : list) { observer.update(); } } }
客户端对象
public class Client { public static void main(String[] args) { // 建立主题对象 Subject concreteSubject = new ConcreteSubject(); concreteSubject.attach(new ConcreteObserver(concreteSubject, "安倍晴明")); concreteSubject.attach(new ConcreteObserver(concreteSubject, "神乐")); concreteSubject.attach(new ConcreteObserver(concreteSubject, "源博雅")); concreteSubject.SubjectState = "结界突破!"; concreteSubject.nodifyObservers(concreteSubject.SubjectState); } }
运行结果接口
我是观察者安倍晴明, 个人状态是Initial Attached an observer 我是观察者神乐, 个人状态是Initial Attached an observer 我是观察者源博雅, 个人状态是Initial Attached an observer 我是观察者安倍晴明, 个人状态是结界突破! 我是观察者神乐, 个人状态是结界突破! 我是观察者源博雅, 个人状态是结界突破!
在主题(被观察者)中,定义了一个集合用来存放观察者,编写了注册attach()和移除detach()观察者的方法,这体现了一对多的关系,也提供了能够控制观察者的方式
关键点1:每一个观察者须要被保存到主题(被观察者)的集合中,而且被观察者提供添加和删除的方式事件
观察者和被观察者之间的交互活动。在添加一个观察者时,把被主题(被观察者)对象以构造函数的形式给传入了观察者。最后主题(被观察者)执行nodifyObservers()方法,触发全部观察者的update()方法以更新状态
关键点2:被主题(被观察者)把本身传给观察者,当状态改变后,经过遍历或循环的方式逐个通知列表中的观察者
但这里有个问题,主题(被观察者)是经过构造函数参数的形式,传给观察者的,而观察者对象时被attach()到主题(被观察者)的list中
关键点3:虽然解耦了观察者和主题(被观察者)的依赖,让各自的变化不大影响另外一方的变化,可是这种解耦并不完全,没有彻底解除二者之间的耦合
关键点4:在事件中,订阅者和发布者之间是经过把事件处理程序绑定到委托,并非把自身传给对方。因此解决了观察者模式中不彻底解耦的问题
观察者模式,必然涉及到2委托和事件这两种类型
委托就是可把方法当作另外一个方法参数来传递,须要注意方法签名。委托能够看作是方法的抽象,也就是方法的“类”,一个委托的实例能够是一个或者多个方法。咱们能够经过+=或者-=把方法绑定到委托或者从委托移除
事件是一种特殊的委托。首先事件也是委托,只是在声明事件的时候,须要加上event,若是你用reflector去看一个事件,你会发现里面就3样东西,一个Add_xxxx方法,一个Remove_xxx方法,一个委托。和上面所定义主题(被观察者)时的注册attach()和移除detach()有些联系
实际上.Net的事件机制就是观察者模式的一种体现,而且是利用委托来实现。本质上事件就是一种订阅-发布模型也就是观察者模式,这种机制中包含2个角色,一个是发布者,一个是订阅者。发布者类也就相似于主题(被观察者),发布者类包含事件和委托定义,以及其之间的关系,发布者类的对象调用事件通知其余订阅者。而订阅者类也就相似于观察者,观察者接受事件,而且提供处理的逻辑。也就是说,订阅者对象(观察者)中的方法会绑定到发布者(被观察者)对象的委托中,一旦发布者(被观察者)中事件被调用,发布者(被观察者)就会调用委托中绑定的订阅者(观察者)的处理逻辑或者说是处理程序,这就是经过观察者模式实现的事件
在普通的观察者模式中,解耦并不完全,那么在事件的发布订阅模型中,解耦完全吗?为何?
答案是确定的。由于在事件中,订阅者和发布者之间是经过把事件处理程序绑定到委托,并非把自身传给对方。因此解决了观察者模式中不彻底解耦的问题
经过委托绑定方法来实现观察者模式,会不会有什么隐患?
有的,经过+=去把方法绑定到委托,很容易忘记-=。若是只绑定不移除,这个方法会一直被引用。咱们知道GC去回收的时候,只会处理没有被引用的对象,只要是还被引用的对象时不会被回收掉的。因此若是在长期不关闭的系统中(好比监控系统),大量的代码使用+=而不-=,运行时间长之后有可能会内存溢出
事件,委托,观察者模式之间的关系
委托是一种类型,事件是一种特殊的委托,观察者模式是一种设计模式,事件的机制是观察者模式的一种实现,其中订阅者和发布者经过委托实现协同工做