班主任来啦之观察者模式,事件委托等Java实现---如果你还不懂,看完此文,就一定会懂

班主任来啦!

小A对小B说:“今天真是笑死人了,我们班一位同学在仔细的时候看NBA球赛,被班主任抓了个正着。班主任脸都绿了,哈哈,真是笑死我了。

小B说:”啊,你们怎么同学怎么敢在课上看电视啊?“

小A说:”没有的,他们那帮子男生经常自习的时候看球赛的。我们班有个女生坐在前排,那些男生就给她送写小礼物啊什么的。班主任来了,那个女生就去通知敲一下桌子。“

小B说:”好吧。这也行。那今天怎么会有人被抓?“

小A说:”这是因为刚好班主任来的时候,那个女生去上厕所了。结果一个看漫画的男生没被抓,那个看NBA球赛的男生被抓了。手机都被没收了呢!”

小B说:“好吧。你说的这个场景,让我想起了一个设计模式,叫做观察者模式。要不给你讲讲?”

小A吐血,倒地不起。。。。。。

观察者模式

我们先来看看观察者模式的定义:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。在上面的场景中,观察者就是指各位苦逼同学啦,而监听的主题对象就是万恶的班主任了,班主任来的时候,通知者通知所有的同学,那么所有的同学都去自动更新自己,看NBA球赛的停下来看书,看漫画的也停下来看书。怎么样?是不是炒鸡形象,下面我们就用代码来实现上面场景里面发生的事情:

import java.util.*;

//负责帮忙监听的女同学
class GirlClassMate {
	private String action;         //前台秘书发现的情况

	//给她送过礼的男同学们
	private ArrayList<NbaWatcher> observers = new ArrayList<NbaWatcher>();

	//增加,就是有几个同学请她帮们关照,就在集合中增加几个对象
	public void Attach(NbaWatcher observer) {
		observers.add(observer);
	}

	//从关照对象中删除对象
	public void Delete(NbaWatcher observer) {
		observers.remove(observer);
	}

	//通知关照看NBA的每一位同学,班主任来啦!
	public void Notify() {
		for (NbaWatcher observer : observers) {
			observer.Update();
		}
	}

	public void setAction(String action) {
		this.action = action;
	}

	public String getAction() {
		return action;
	}
}

//看NBA的同学
class NbaWatcher {
	private String name;          //该同学的名字
	private GirlClassMate wodi;   //前排卧底MM
	public void Update() {
		// TODO Auto-generated method stub
		System.out.println(wodi.getAction() + name + "别看球赛啦,继续学习!");
	}
	public NbaWatcher(String name, GirlClassMate wodi) {
		this.name = name;
		this.wodi = wodi;
	}
}

public class MainClass {
	public static void main(String[] args) {
		GirlClassMate MM = new GirlClassMate();     //前台MM对象
		NbaWatcher diaosi1 = new NbaWatcher("屌丝1", MM);   //看股票的同事1
		NbaWatcher diaosi2 = new NbaWatcher("屌丝2", MM);   //看股票的同事1

		//将两位屌丝同事加进前台MM的关照对象列表中
		MM.Attach(diaosi1);
		MM.Attach(diaosi2);

		//前台MM发现老板回来了
		MM.setAction("班主任回来啦!");

		//通知关照列表中的每一位同事,老板回来了
		MM.Notify();
	}
}

输出结果:

班主任回来啦!屌丝1别看球赛啦,继续学习!
班主任回来啦!屌丝2别看球赛啦,继续学习!

你来评一评,这代码写的怎么样?肯定不好啦!前排女同学对象依赖于具体的看NBA同学对象,而NBA同学对象依赖于前排女同学对象。那么这样就形成了一种双向耦合的关系。在一段代码里面,耦合度过高可不是什么好事。用依赖倒转原则专业的话来说就是:具体应该依赖于抽象,抽象不应该依赖于具体。按照这个原则,我们将看NBA球赛的观察者,看漫画的观察者等等抽象出来一个观察者类。而无论是前排MM通知者,还是班主任这个通知者都是通知者,所以也可以抽象为一个通知者类。改进之后的代码如下:

import java.util.*;

//通知者,可能是班主任自己,也可能是前排女同学
abstract class Notifier {

	private ArrayList<Observer> observers = new ArrayList<Observer>();

	public void Attach(Observer observer) {
		observers.add(observer);
	}

	public void Delete(Observer observer) {
		observers.remove(observer);
	}

	//通知关照同学列表中每一位同事,班主任来了
	public void Notify() {
		for (Observer observer : observers) {
			observer.Update();
		}
	}

	abstract public void setAction(String action);
	abstract public String getAction();
}

class Boss extends Notifier{

	private String action;         //通知者发现的情况

	//老板发现的情况
	public void setAction(String action) {
		this.action = action;
	}

	public String getAction() {
		return action;
	}
}

class GirlClassMate extends Notifier{
	private String action;         //通知者发现的情况

	//前台MM发现的情况
	public void setAction(String action) {
		this.action = action;
	}

	public String getAction() {
		return action;
	}
}

//Observer师祖
abstract class Observer {
	protected String name;          //该同学的名字
	protected Notifier notifier;        //事件通知者
	abstract void Update();

	public Observer(String name, Notifier notifier) {
		this.name = name;
		this.notifier = notifier;
	}

}

//看NBA的的同事
class NbaWatcher extends Observer{

	public NbaWatcher(String name, Notifier notifier) {
		super(name, notifier);
		// TODO Auto-generated constructor stub
	}

	public void Update() {
		// TODO Auto-generated method stub
		System.out.println(notifier.getAction() + name + "别看球赛啦,继续学习!");
	}
}

//看世界杯的同事
class ComicReader extends Observer{

	public ComicReader(String name, Notifier notifier) {
		super(name, notifier);
		// TODO Auto-generated constructor stub
	}

	public void Update() {
		// TODO Auto-generated method stub
		System.out.println(notifier.getAction() + name + "别看漫画啦,继续学习");
	}
}

public class MainClass {
	public static void main(String[] args) {

		Notifier tuhao = new Boss();     //通知者换成班主任自己了
		Observer diaosi1 = new NbaWatcher("倒霉的屌丝1", tuhao);   //看NBA的同学
		Observer diaosi2 = new ComicReader("幸运的屌丝2", tuhao);   //看NBA的同学

		//将两位屌丝同事加进前台MM的关照对象列表中
		//tuhao.Attach(diaosi1);  //倒霉的屌丝1,没有加进老板的关照列表,所以被抓住了
		tuhao.Attach(diaosi2);

		//前台MM发现老板回来了
		tuhao.setAction("班主任我回来啦!");

		//通知关照列表中的每一位同事,老板回来了
		tuhao.Notify();
	}
}

观察者模式的不足之处

“上面该机的代码中抽象通知者还是依赖了抽象观察者,万一没有抽象观察者,那岂不是功能都完成不了啦!还有你这上面代码写的,所以对象更新的动作都一样的。万一我对象更新不一样呢?比如,看NBA球赛的听见班主任来了就跑去上厕所,而看漫画的听见班主任来了就继续看书。代码又应该怎么写呢?”小A,揉了揉惺忪的睡眼,疑惑地问道。

小B说:“我去,我还以为你睡着了呢!原来你在听啊!我太高兴了。下面我们就利用一种叫做“事件委托”的东东去解决这个问题哈!”

小A说:“我滴个神,什么叫事件委托啊?”

观察者模式改进-反射版事件委托

小B说:“你先别着急哈!我们先来看看该怎么用哈!”

代码中,我们去除了抽象观察者这个类,由客户端去决定需要通知哪个观察者。PS:Java中是没有像c#里面的delegation,所以我用Java中的反射来实现,见如下代码。

import java.util.*;
import java.lang.reflect.*;

//通知者,可能是老板,也可能是前台秘书
abstract class Notifier {
	protected Method Update;
	abstract public void setAction(String action);
	abstract public void Notify(Object object);
}

class Boss extends Notifier{

	private String action;         //通知者发现的情况

	//老板发现的情况
	public void setAction(String action) {
		this.action = action;
	}

	public void Notify(Object object) {
		if (Update != null) {
			try {
				Update.invoke(object, action);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

class GirlClassMate extends Notifier{
	private String action;         //通知者发现的情况
	public Method Update;          //反射事件

	//老板发现的情况
	public void setAction(String action) {
		this.action = action;
	}

	public void Notify(Object object) {
		if (Update != null) {
			try {
				Update.invoke(object, action);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

//看股票的同事
class NbaWatcher {

	protected String name;          //该同事的名字
	protected Notifier notifier;        //前台卧底MM

	public NbaWatcher(String name, Notifier notifier) {
		this.name = name;
		this.notifier = notifier;
	}

	public void CloseNbaWatcher(String action) {
		// TODO Auto-generated method stub
		System.out.println(action + name + "别看球赛啦,继续学习");
	}
}

//看世界杯的同事
class ComicReader {

	protected String name;          //该同事的名字
	protected Notifier notifier;        //前台卧底MM

	public ComicReader(String name, Notifier notifier) {
		this.name = name;
		this.notifier = notifier;
	}

	public void CloseComicReader(String action) {
		// TODO Auto-generated method stub
		System.out.println(action + name + "别看漫画啦,继续学习");
	}
}

public class MainClass {
	public static void main(String[] args) {

		Notifier tuhao = new Boss();
		NbaWatcher diaosi1 = new NbaWatcher("倒霉的屌丝1", tuhao);
		ComicReader diaosi2 = new ComicReader("幸运的屌丝2", tuhao);  

		tuhao.setAction("班主任我回来啦!");

		try {
			tuhao.Update = diaosi1.getClass().getMethod("CloseNbaWatcher", new Class[] {String.class});
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		tuhao.Notify((Object)diaosi1);

		try {
			tuhao.Update = diaosi2.getClass().getMethod("CloseComicReader", new Class[] {String.class});
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		tuhao.Notify((Object)diaosi2);
	}
}

发射实现委托核心:

protected Method Update;

if (Update != null) {
			try {
				Update.invoke(object, action);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

try {
			tuhao.Update = diaosi2.getClass().getMethod("CloseComicReader", new Class[] {String.class});
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		tuhao.Notify((Object)diaosi2);

右上面代码可以看出,反射能够实现根据类的不同而调用不同的方法。就好像是C#中,一个委托可以搭载多个方法,所有方法一次被唤起。感觉上,也有点像c语言里面的钩子函数。

后继

小A说:哇!小B你好厉害哦,我真的懂了观察模式诶,另外发射模式真的好好用啊!

小B说:O(∩_∩)O哈哈~你学到东西就好!其实该感谢本文作者的吐血整理,我,笑了~~~~~~~你们都懂了就好!

时间: 2024-08-11 07:49:41

班主任来啦之观察者模式,事件委托等Java实现---如果你还不懂,看完此文,就一定会懂的相关文章

常用设计模式之观察者模式 + 事件委托

常用设计模式之观察者模式 + 事件委托 作用及UML (摘自<大话设计模式>) Code 1 abstract class Subject{ 2 protected String state; 3 public void setState(String state){this.state = state;} 4 public String getState(){return this.state;} 5 6 private List<Observer> observers = ne

大话设计模式-观察者模式/事件委托

观察者模式 观察者模式又称发布-订阅模式,其定义了一种多对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能自动更新自己. 观察者模式的动机 将一个系统分割成一系列相互协作的类有一个很不好的副作用就是需要维护相关对象间的一致性. 我们不希望为了维持一致性而使各类紧密耦合,这样会给维护.扩展和重用都带来不便. 当一个对象的改变需要同时改变其他对象而且他不知道具体有多少对象有待改变时,就应该考虑使用观察者模式. 当一个抽象模型有两个方面

观察者设计模式 Vs 事件委托(java)

观察者设计模式 Vs 事件委托 转载请注明原博客地址: http://blog.csdn.net/gdutxiaoxu/article/details/51824769 源码下载地址: http://download.csdn.net/detail/gdutxiaoxu/9567209 本篇博客主要讲解一下几个问题 什么是观察者模式 观察者模式的优缺点 如何看待观察者模式的缺点 事件的委托 什么是观察者模式 简单来说,当有多个观察者想同时观察同一个主题对象的时候,当主题对象的 状态发生变化,观察

javascript事件委托与&quot;坑&quot;

问题 这是在工作中遇到的一个问题: 一个textarea文本框,需要动态监听输入文本个数 方案 通过谷歌查到一种完美的兼容方法 "如果使用 onkeydown.onkeypress.onkeyup 这个几个键盘事件来监测的话,监听不了右键的复制.剪贴和粘贴这些操作,处理组合快捷键也很麻烦 因此这篇文章向大家介绍一种完美的解决方案:结合 HTML5 标准事件 oninput 和 IE 专属事件 onpropertychange 事件来监听输入框值变化." 引用自 http://www.c

一场武林盟主争霸赛-观察者模式PK委托事件技术

设计模式中提到观察者模式又叫做发布-订阅(Publish-订阅)模式.它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有 观察者对象,使它们能够自动更新自己. C#中提到,委托是对函数的封装,可以当作给方法的特征指定一个名称.而事件则是委托的一种特殊形式,当发生有意义的事情时,事件对象处理通知过程.事件其实就是设计模式中观察者模式在.NET中的一种实现方式. 委托就是一种引用方法的类型.一旦为委托分配了方法,委托将与该方法具有完全相同的

利用事件委托弥补观察者模式不足

前两篇我们自己首先实现了一个观察者模式,我们再利用Java自带的接口和类实现了观察者模式,但其实两种观察者模式存在不足的地方.之前两种观察者模式的观察者(订阅者)都是实现了一个同一个接口,实现了接口中的update方法,但是如果两个观察者风马牛不相及,完全无关呢?或者他们的方法名不一样这个时候该怎么办呢?<大话设计模式>中C#提供了事件委托,但在Java中比没有提供.此时,我们可以利用Java的反射机制来实现事件委托从而来弥补观察者模式的不足. 我们先来看看客户端的测试代码,直观的感受一下和之

观察者模式与事件委托

情景 平时很多人都会用新浪微博, 关注女神动态, 女神就是通知者,也叫主题, 而关注女神的这些人,就是观察者,也叫订阅者, 既然订阅了女神的动态, 如果女神有新的动态, 我们就会想通过某一个渠道被通知, 这种交互方式就是观察者模式 常见的使用场景; spring中的event, listener等都是观察者模式 代码实现 /** * 通知者, 也是主题发布者, 就是为了被观察或者订阅的, * 主题如果状态发生改变,就会通知所有的订阅者(观察者) */ public interface Subje

在Unity中使用事件/委托机制(event/delegate)进行GameObject之

欢迎来到unity学习.unity培训.unity企业培训教育专区,这里有很多U3D资源.U3D培训视频.U3D教程.U3D常见问题.U3D项目源码,[狗刨学习网]unity极致学院,致力于打造业内unity3d培训.学习第一品牌. 一对多的观察者模式机制有什么缺点? 如果你对如何在Unity中使用事件/委托机制还不太了解,建议您查看我的前一篇文章:[Unity3D技巧]在Unity中使用事件/委托机制(event/delegate)进行GameObject之间的通信 在前一篇博客里面,我们写到

【Unity3D技巧】在Unity中使用事件/委托机制(event/delegate)进行GameObject之间的通信

作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 引子 在前面两篇文章: [Unity3D基础教程]给初学者看的Unity教程(四):通过制作Flappy Bird了解Native 2D中的RigidBody2D和Collider2D [Unity3D基础教程]给初学者看的Unity教程(三):通过制作Flappy Bird了解Native 2D中的Sprite,Animation 我们了解