版权声明:作者: 阿顾, 转载请写明出处, 谢谢 https://blog.csdn.net/u010452388/article/details/82962592
故事情景
首先介绍下故事的三位同学,阿顾、蛋蛋和洋洋,蛋蛋,洋洋喜欢玩游戏,但是又生怕班主任回来了被抓到,所以他们就找到了阿顾同学帮他们把风,但是阿顾同学不是谁都通知的,只有到阿顾那里登记的,阿顾同学才会通知这些登记的人,下面我们来模拟下整个流程:
蛋蛋说:“阿顾,我在玩dota,班主任回来了,通知一声”
阿顾说:“好的,我记录一下”
洋洋说:“阿顾,我在玩王者荣耀,班主任回来了,通知一声”
阿顾说:“好的,我记录一下”
阿顾此时正在把风,过了一会,发现班主任回来了,立马通知刚刚在这里登记的蛋蛋和洋洋同学
蛋蛋立即关闭dota,继续学习;洋洋立即关闭王者荣耀,继续学习(流程结束)
到这里,我们看一下代码
目录
一 观察者模式
1.1 代码结构
1.2 主题
主题是一个接口,提供了观察者抽象类添加方法,移除方法,以及通知功能
public interface Subject {
//增加观察者
public void add(Observer observer);
//移除观察者
public void remove(Observer observer);
//通知观察者
public void notifyObserver();
}
1.3 观察者(抽象类)
/**
* 观察者(抽象类)
*/
public abstract class Observer {
//抽象方法(停止做某事)
public abstract void stopDoingSomeThing();
}
1.4 阿顾同学
这里实现了主题,并且添加了一个观察者抽象类的集合,所以登记的同学都放到这个集合里,如果发现班主任回来了,直接直接执行通知方法(遍历集合里的同学)
public class AguSubject implements Subject {
//主题状态
private String subjectState;
public String getSubjectState() {
return subjectState;
}
public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
}
//观察者列表(所有需要通知的对象都会放到这个集合里)
private List<Observer> observerList =new ArrayList<Observer>();
//添加观察者
public void add(Observer observer) {
observerList.add(observer);
}
//移除观察者
public void remove(Observer observer) {
observerList.remove(observer);
}
//通知观察者
public void notifyObserver() {
for (Observer observer : observerList) {
//父类执行这个方法,执行的是子类重写的方法
observer.stopDoingSomeThing();
}
}
}
1.5 蛋蛋同学
public class DanDanObserver extends Observer {
//姓名
private String name;
//阿顾同学
private AguSubject subject;
//有参构造函数
public DanDanObserver(String name, AguSubject subject) {
this.name = name;
this.subject = subject;
}
//重写父类方法
public void stopDoingSomeThing() {
System.out.println(subject.getSubjectState() + this.name + "关闭了<dota2>,继续学习");
}
}
1.6 洋洋同学
public class YangYangObserver extends Observer {
//姓名
private String name;
//阿顾同学
private AguSubject subject;
//有参构造函数
public YangYangObserver(String name,AguSubject subject){
this.name=name;
this.subject=subject;
}
//重写父类方法
public void stopDoingSomeThing() {
System.out.println(subject.getSubjectState()+this.name+"关闭了<王者荣耀>,继续学习");
}
}
1.7 测试
public class AppStart {
public static void main(String[] args) {
//创建阿顾同学(负责把风)
AguSubject aguSubject = new AguSubject();
//创建蛋蛋
DanDanObserver danObserver = new DanDanObserver("蛋蛋", aguSubject);
//创建洋洋
YangYangObserver yangObserver = new YangYangObserver("洋洋", aguSubject);
//蛋蛋在阿顾同学那登记,如果老师来了通知下
aguSubject.add(danObserver);
//洋洋在阿顾同学那登记,如果老师来了通知下
aguSubject.add(yangObserver);
//阿顾发现老师回来了
aguSubject.setSubjectState("老师回来了----");
//通知所有登记过的同学
aguSubject.notifyObserver();
}
}
1.8 运行结果
1.9 观察者模式的优缺点
1.9.1 优点
1. 观察者和主题进行了不错的解耦
1.9.2 缺点
1.主题还是要依赖抽象观察者(Subject里的方法要传入Observer),如果没有抽象观察者呢
2.每个具体的观察者方法都一样(蛋蛋和洋洋里都要重写stopDoingSomething()方法,并且他们的方法名和参数是一样的)
1.9.3 解决缺点
通过事件委托可以解决
二 事件委托
2.1 代码结构
2.2 事件类
这里是把一个对象,对象的方法,方法的参数 封装到事件类中,这样拿到事件,就拿到了对象的方法,就可以直接执行对应的方法了
/**
* 事件类,就是将一个对象,对象的方法,方法中的参数 作为事件类的属性
*/
public class Event {
//要执行方法的对象
private Object object;
//要执行方法的方法名
private String methodName;
//要执行方法的参数
private Object[] params;
//要执行方法的参数的类型
private Class[] paramTypes;
//无惨构造函数
public Event() {
}
public Event(Object object, String methodName, Object... args) {
this.object = object;
this.methodName = methodName;
this.params = args;
generateParamTypes(args);
}
//获取执行方法的参数的类型
public void generateParamTypes(Object[] args) {
this.paramTypes = new Class[args.length];
for (int i = 0; i < args.length; i++) {
paramTypes[i] = args[i].getClass();
}
}
//方法的执行
public void invoke() throws Exception {
//通过反射以及方法名和参数类型获取到对应的方法
Method method = object.getClass().getMethod(this.getMethodName(), this.getParamTypes());
if(null==method){
return;
}
//方法执行
method.invoke(this.getObject(),this.getParams());
}
//get和set方法省略...
}
2.3 事件处理类
这里又将Event的集合封装到EventHandler中
public class EventHandler {
//事件列表(就是传进来某个对象的方法的一个集合)
private List<Event> eventList;
public EventHandler() {
eventList = new ArrayList<Event>();
}
//添加某个对象要执行的方法,及参数
public void addEvent(Object object, String methodName, Object... args) {
Event event = new Event(object, methodName, args);
eventList.add(event);
}
//通知所有观察者
public void notifyObserver() throws Exception {
for (Event e : eventList) {
e.invoke();
}
}
}
2.4 通知者(抽象类)
这里又将EventHandler封装到Notifier中
public abstract class Notifier {
private EventHandler eventHandler = new EventHandler();
public EventHandler getEventHandler() {
return eventHandler;
}
public void setEventHandler(EventHandler eventHandler) {
this.eventHandler = eventHandler;
}
/**
* 增加需要被通知的对象
* @param object 要执行方法的对象
* @param methodName 执行方法的方法名
* @param args 执行方法的参数
*/
public abstract void addListener(Object object, String methodName, Object... args);
//通知
public abstract void notifyObserver() throws Exception;
}
2.5 阿顾同学
public class AguNotifier extends Notifier {
//添加
public void addListener(Object object, String methodName, Object... args) {
System.out.println("有新的同学委托阿顾");
this.getEventHandler().addEvent(object, methodName, args);
}
//通知
public void notifyObserver() throws Exception {
System.out.println("======阿顾同学正在观察...班主任来了没======");
Thread.sleep(2000);
System.out.println("过了2秒后,阿顾通知:班主任人来了");
this.getEventHandler().notifyObserver();
}
}
2.6 蛋蛋同学
public class DanDanObserver {
public DanDanObserver(){
System.out.println("蛋蛋 正在打dota2,时间:"+new Date());
}
public void stopPlayDota2(String book){
System.out.println("蛋蛋 关闭了dota2,继续学习"+book+",时间:"+new Date());
}
}
2.7 洋洋同学
public class YangYangObserver {
public YangYangObserver() {
System.out.println("洋洋 正在打王者荣耀,时间:"+new Date());
}
public void stopKingGlory(Double javaVersion) {
System.out.println("洋洋 关闭了王者荣耀,继续研究java"+javaVersion+"新特性,时间:" + new Date());
}
}
2.8 测试
public class AppStart {
public static void main(String[] args) {
//专门把风的阿顾同学
AguNotifier aguNotifier = new AguNotifier();
//玩dota2的蛋蛋同学
DanDanObserver danDanObserver = new DanDanObserver();
//玩王者的洋洋同学
YangYangObserver yangYangObserver = new YangYangObserver();
//玩dota2的蛋蛋让阿顾帮忙看一下,如果班主任来了通知下
aguNotifier.addListener(danDanObserver,"stopPlayDota2","<java编程思想>");
//玩王者的洋洋让阿顾帮忙看一下,如果班主任来了通知下
aguNotifier.addListener(yangYangObserver,"stopKingGlory",1.8);
try {
//阿顾开始通知
aguNotifier.notifyObserver();
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.9 运行结果
三 参考文献
1.大话设计模式
2.https://blog.csdn.net/gdutxiaoxu/article/details/51824769