参考
https://blog.youkuaiyun.com/caoxiaohong1005/article/details/79019706
1 准确定义
定义了一种一对多的依赖关系,让多个观察者对象同事监听某一个主题的对象。这个主题对象在状态在发生变化时,会通知所有的观察者对象,让它们能够自动更新自己。
2 使用的意义
讲一个系统分割成一系列相互协作的类有一个不好的副作用,那就是需要维护相关对象的一致性。我们不希望为了维持一致性而使得各类紧密耦合,这样会给维护、扩展、重用带来不便。而观察者模式的关键对象是主题Subject和观察者Observer,一个Subject可以有多个依赖它的Observer,一旦Subject发生变化,所有的Observer都可以得到通知。
3、适用场景
3.1、当一个对象的改变需要同时改变其它对象。
3.2、这个对象并不知道它需要同时改变多少个依赖它的对象。
4、UML图
5、例子
5.1UML图
5.2、code
Client
package designmodel.fourteenthchapter;
/**
* @Author: cxh
* @CreateTime: 18/1/10 09:08
* @ProjectName: JavaBaseTest
*/
public class Client {
public static void main(String[] args) {
Boss boss=new Boss();
NBAObserver nbaObserver=new NBAObserver("李明浩",boss);
TVObserver tvObserver=new TVObserver("李沁",boss);
//add
boss.add(nbaObserver);
boss.add(tvObserver);
//delete
//boss状态转变,通知观察者
boss.setSubjetctState("领导回来了");
boss.notifyObservers();
}
}
Subject
package designmodel.fourteenthchapter;
/**
* @Author: cxh
* @CreateTime: 18/1/9 23:29
* @ProjectName: JavaBaseTest
*/
public abstract class Subject {
abstract void add(Observer observer);
abstract void delete(Observer observer);
abstract void notifyObservers();
private String subjetctState;
//获取主题状态
public String getSubjetctState() {
return subjetctState;
}
//设置主题状态
public void setSubjetctState(String subjetctState) {
this.subjetctState = subjetctState;
}
}
Boss
package designmodel.fourteenthchapter;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: cxh
* @CreateTime: 18/1/10 09:11
* @ProjectName: JavaBaseTest
*/
public class Boss extends Subject{
private List<Observer> list=new ArrayList<>();
//增加观察者
public void add(Observer observer){
list.add(observer);
}
//删除观察者
public void delete(Observer observer){
list.remove(observer);
}
//通知
public void notifyObservers(){
for(Observer s:list)
s.update();
}
}
Observer
package designmodel.fourteenthchapter;
/**
* @Author: cxh
* @CreateTime: 18/1/9 23:17
* @ProjectName: JavaBaseTest
*/
public interface Observer {
void update();
}
NBAObserver
package designmodel.fourteenthchapter;
/**
* @Author: cxh
* @CreateTime: 18/1/9 23:28
* @ProjectName: JavaBaseTest
*/
public class NBAObserver implements Observer {
private Subject subject;//关注主题
private String name;//观察者名字
public NBAObserver(String name,Subject subject){//参数Subject体现了:具体依赖抽象原则
this.name=name;
this.subject=subject;
}
@Override
public void update() {
System.out.println(subject.getSubjetctState()+","+name+","+"快继续工作~");
}
}
TVObserver
package designmodel.fourteenthchapter;
/**
* @Author: cxh
* @CreateTime: 18/1/9 23:45
* @ProjectName: JavaBaseTest
*/
public class TVObserver implements Observer {
private String name;//看电视的人名字
private Boss subject;//主题
public TVObserver(String name,Boss subject){
this.name=name;
this.subject=subject;
}
@Override
public void update() {
System.out.println(subject.getSubjetctState()+","+name+","+"快继续工作~");
}
}
输出:
领导回来了,李明浩,快继续工作~
领导回来了,李沁,快继续工作~
Process finished with exit code 0
6 观察者模式不足
- 抽象通知者仍然依赖抽象观察者
- 每个具体观察者被通知时,通知方法名必须一样,而实际中很难一样
7 优化观察者模式:事件委托实现
- 事件委托解决的问题:一个委托可以搭载多个方法,所有方法被一次唤起。更重要的是委托可以使得委托对象所搭载的方法并不属于同一个类,从而实现通知者和抽象观察者解耦。
- 委托是什么:是一种引用方法的类型。一旦为委托分配了方法,则委托和该方法拥有完全相同的行为。委托方法的使用可以和其它任何方法一样,具有参数和返回值。委托可以看作是对函数的抽象 ,是函数的“类”,委托的实例将代表一个具体的函数。
- 委托实质:用反射来实现。
- 委托事件的前提:委托对象所搭载的所有方法必须具有相同的原形和形式,也就是拥有相同的参数列表和返回值类型。
8 委托代码实现观察者模式
8.1 应用场景
办公室里面有两类同事:
(1) 看NBA赛事直播的男人们 & 看电视剧的女人们。
(2) 通知忙里偷闲的同事,即:领导回来消息的岗哨。
通过使用委托,实现观察者中岗哨和观察者之间解耦。
8.2 code
Client
package designmodel.delegate;
import java.util.Date;
/**
* @Author: cxh
* @CreateTime: 18/1/12 16:40
* @ProjectName: JavaBaseTest
*/
public class Client {
public static void main(String[] args) {
//观察者. 创建时起,开始做自己的事情
NBAObserver nbaObserver=new NBAObserver();
TVObserver tvObserver=new TVObserver();
//主题(通知者)
NotifierA notifierA=new NotifierA();
//为主题添加观察者
notifierA.addListener(nbaObserver,"stopWatchingNBA",new Date());
notifierA.addListener(tvObserver,"stopWatchingTV",new Date());
//主题状态改变,通知观察者
notifierA.notifyX();
}
}
Event
package designmodel.delegate;
import java.lang.reflect.Method;
/**
* @Author: cxh
* @CreateTime: 18/1/10 23:29
* @ProjectName: JavaBaseTest
*/
public class Event{
//要执行方法的对象
private Object object;
//要执行的方法名称
private String methodName;
//要执行方法的参数
private Object[] params;
//要执行方法的参数类型
private Class[] paramType;
//两个构造函数
public Event(){}
public Event(Object object,String methodName,Object... args){
this.object=object;
this.methodName=methodName;
this.params=args;
//获取参数类型
getParaTypes(args);
}
private void getParaTypes(Object[] params){
int size=params.length;
this.paramType=new Class[size];//4个私有变量,只有这个变量实现了深拷贝
for(int i=0;i<size;i++)
paramType[i]=params[i].getClass();
}
//执行该对象的方法
public void invoke() throws Exception{
Method method=object.getClass().getMethod(getMethodName(),getParamType());
if(null==method)
return;
method.invoke(getObject(),getParams());
}
//get,set方法
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Object[] getParams() {
return params;
}
public void setParams(Object[] params) {
this.params = params;
}
public Class[] getParamType() {
return paramType;
}
public void setParamType(Class[] paramType) {
this.paramType = paramType;
}
}
EventHandler
package designmodel.delegate;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: cxh
* @CreateTime: 18/1/12 11:23
* @ProjectName: JavaBaseTest
*/
public class EventHandler {
//保存了很多event的引用
private List<Event> objects;
public EventHandler(){
objects=new ArrayList<>();
}
//添加某个event
public void addEvent(Object object,String name,Object... args){
objects.add(new Event(object,name,args));
}
//触发所有引用的event
public void notifyEvents() throws Exception{
for(Event e:objects)
e.invoke();
}
}
NBAObserver
package designmodel.delegate;
import java.util.Date;
/**
* @Author: cxh
* @CreateTime: 18/1/12 16:30
* @ProjectName: JavaBaseTest
*/
public class NBAObserver{
public NBAObserver(){
System.out.println("正在观看NBA比赛!当前时间为:"+new Date());
}
public void stopWatchingNBA(Date date){
System.out.println("领导回来了,快关闭NBA赛事直播!当前时间为:"+date);
}
}
TVObserver
package designmodel.delegate;
import java.util.Date;
/**
* @Author: cxh
* @CreateTime: 18/1/12 16:37
* @ProjectName: JavaBaseTest
*/
public class TVObserver {
public TVObserver(){
System.out.println("正在观看电视剧<<甄嬛传>>,当前时间为:"+new Date());
}
public void stopWatchingTV(Date date){
System.out.println("领导回来了,快关闭电视剧播放.当前时间为:"+date);
}
}
Notifier
package designmodel.delegate;
/**
* @Author: cxh
* @CreateTime: 18/1/12 11:36
* @ProjectName: JavaBaseTest
*/
public abstract class Notifier {
private EventHandler eventHandler=new EventHandler();
//增加需要帮忙放哨的同事
public abstract void addListener(Object object,String name,Object... args);
//告诉所有需要帮忙放哨的同事:领导回来啦
public abstract void notifyX();
//get,set
public EventHandler getEventHandler() {
return eventHandler;
}
public void setEventHandler(EventHandler eventHandler) {
this.eventHandler = eventHandler;
}
}
NotifierA
package designmodel.delegate;
/**
* @Author: cxh
* @CreateTime: 18/1/12 16:13
* @ProjectName: JavaBaseTest
*/
public class NotifierA extends Notifier{
@Override
public void addListener(Object object, String name, Object... args) {
getEventHandler().addEvent(object,name,args);
}
@Override
public void notifyX(){
try{
getEventHandler().notifyEvents();
}catch (Exception e){
System.out.println("通知同事时出错!!!");
}
}
}