博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
观察者模式
阅读量:2434 次
发布时间:2019-05-10

本文共 7370 字,大约阅读时间需要 24 分钟。

  观察者模式(发布-订阅模式):定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。

                  这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
  
  当一个对象的改变需同时改变其它对象的时候,而且它不知道具体有多少对象有待改变时,应考虑使用观察者模式。
                    
 优点:
  第一、观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体观察者列表,
          每一个具体观察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们
          都有一个共同的接口。由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。 
          如果被观察者和观察者都被扔到一起,那么这个对象必然跨越抽象化和具体化层次。 
  第二、观察者模式支持广播通讯。被观察者会向所有的登记过的观察者发出通知.
 
 缺点:
   第一、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
   第二、如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。
            在使用观察者模式是要特别注意这一点。 
   第三、如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
   第四、虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使
           观察者知道所观察的对象是怎么发生变化的。 
   第五、抽象通知者依赖于抽象观察者,没有抽象观察者的接口,通知功能就完成不了。另外就是每个具体
            的观察者不一定是更新的方法update()要调用。

 

 

/** * 抽象观察者:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。 * 抽象观察者一般用一个抽象类或者一个接口实现,通常包含一个更新方法update()。 *  */public abstract class Observer {		public abstract void update();	}

 

/** * 具体观察者:实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。 * 			 具体观察者角色可以保存一个指向具体主题对象的引用。 */public class ConcreteObserver extends Observer {		private String name;	private String observerState;	private ConcreteSubject subject;		public ConcreteObserver(String name,ConcreteSubject subject){		this.name = name;		this.subject = subject;	}	@Override	public void update() {				this.observerState = subject.getSubjectState();				System.out.println("观察者"+name+"的新状态是"+observerState);	}	public ConcreteSubject getSubject() {		return subject;	}	public void setSubject(ConcreteSubject subject) {		this.subject = subject;	}}

 

/** * 主题或抽象通知者:一般用一个抽象类或一个接口实现,把所有对观察者对象的引用保存在一个聚集里, * 		每个主题都可以有任何数量的观察者,可以增加或删除观察者对象。 */public abstract class Subject {		private List
observerList = new ArrayList
(); //增加观察者 public void attach(Observer observer){ observerList.add(observer); } // 移除观察者 public void remove(Observer observer){ observerList.remove(observer); } // 通知 public void notice(){ for(Observer observer:observerList){ observer.update(); } }}

 

/** * 具体的主题或具体的通知者:将有关状态存入具体的观察者对象,在具体主题的内部状态改变时, * 		          给所有登记过的观察者发出通知。 */public class ConcreteSubject extends Subject {	// 具体被观察者的状态	private String subjectState;	public String getSubjectState() {		return subjectState;	}	public void setSubjectState(String subjectState) {		this.subjectState = subjectState;	}}

 

public class Main {	public static void main(String[] args) {				// 主题对象(被观察者)		ConcreteSubject subject = new ConcreteSubject();		// 添加观察者对象		subject.attach(new ConcreteObserver("X",subject));		subject.attach(new ConcreteObserver("Y",subject));		subject.attach(new ConcreteObserver("Z",subject));				// 主题对象状态更新		subject.setSubjectState("ABC");				// 发出通知		subject.notice();	}}

 

 

观察者模式实例:(老板-同事)

 

 

/** * 抽象观察者 * */public abstract class Observer {		protected String name;		// 对通知者的引用	protected Subject subject;		public Observer(String name,Subject subject){		this.name = name;		this.subject = subject ;	}		// 抽象更新方法	public abstract void update();}

 

/** * 看NBA的同事:具体的观察者,实现观察者抽象类 * */public class NBAObserver extends Observer {	public NBAObserver(String name, Subject subject) {		super(name, subject);	}	@Override	public void update() {		System.out.println(subject.getSubjectState()				    +" "+name+"关闭NBA直播,继继工作");	}}

 

/** * 看股票的同事:具体的观察者,实现观察者抽象类 * */public class StockObserver extends Observer {	public StockObserver(String name, Subject subject) {		super(name, subject);	}	@Override	public void update() {		System.out.println(subject.getSubjectState()				    +" "+name+"关闭股票行情,继继工作");	}}

 

/** * 通知者接口 */public interface Subject {			// 添加观察者	public void attach(Observer observer);	public void remove(Observer observer);		// 通知者的状态	public String getSubjectState();	public void setSubjectState(String subjectState);		// 发出通知	public void notice();}

 

/** * 老板:具体的通知者类,实现通知者接口 */import java.util.ArrayList;import java.util.List;public class Boss implements Subject {			// 通知者的状态	private String subjectState;		// 观察者的聚集	private List
observerList = new ArrayList
(); public void attach(Observer observer) { observerList.add(observer); } public String getSubjectState() { return subjectState; } public void remove(Observer observer) { observerList.remove(observer); } public void setSubjectState(String subjectState) { this.subjectState = subjectState; } // 发出通知 public void notice() { for(Observer observer:observerList){ observer.update(); } }}

 

public class Main {	public static void main(String[] args) {				// 老板胡汉三		Boss huhansan = new Boss();				// 看股票的同事		StockObserver tongshi1 = new StockObserver("小王",huhansan);				// 看NBA的同事		NBAObserver tongshi2 = new NBAObserver("小李",huhansan);				huhansan.attach(tongshi1);		huhansan.attach(tongshi2);				// 小李没有被老板通知到,所以移去		huhansan.remove(tongshi2);				// 老板回来了		huhansan.setSubjectState("我胡汉三回来了");				// 发出通知		huhansan.notice();	}}

 

运行结果如下:

 

我胡汉三回来了 小王关闭股票行情,继继工作

 

 

 观察者模式改进:利用委托机制对抽象通知者与抽象观察者依赖的解藕, 可指定不同的通知对象

                           和通知时调用不同的方法。

 

/** * 看NBA的同事:具体的观察者 * */public class NBAObserver {		public void closeNBADirectSeeding(Date date) {		System.out.println("关闭NBA直播,继继工作"+date);	}}

 

/** * 看股票的同事:具体的观察者 * */public class StockObserver{		public void closeStockMarket(String name) {		System.out.println("关闭股票行情,继继工作"+name);	}}

 

/** * 事件类 */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;		this.contractParamTypes(params);	}		// 根据参数数组生成参数类型数组	private void contractParamTypes(Object[] params){		this.paramTypes = new Class[params.length];		for(int i=0;i

 

/** * 若干Event类的载体,同时提供一个所有执行Event类的方法 * */public class EventHandler {		private List
objects; public EventHandler(){ objects = new ArrayList
(); } // 添加某个对象要执行的事件,及需要的参数 public void addEvent(Object object,String methodName,Object... args){ objects.add(new Event(object,methodName,args)); } // 通知所有的对象执行指定的事件 public void notice() throws Exception{ for(Event event:objects){ event.invoke(); } }}

 

/** * 抽象通知者 * */public abstract class Subject {		private EventHandler eventHandler = new EventHandler();		// 添加观察者	public abstract void addListener(Object object,					     String methodName,Object... args);		// 通知所有观察者	public abstract void notice();	public EventHandler getEventHandler() {		return eventHandler;	}	public void setEventHandler(EventHandler eventHandler) {		this.eventHandler = eventHandler;	}}

 

/** * 老板:具体的通知者类,实现通知者接口 */public class Boss extends Subject{	@Override	public void addListener(Object object, String methodName, Object... args) {				// 添加观察者对象		this.getEventHandler().addEvent(object, methodName, args);	}		@Override	public void notice() {				try {						// 对所有观察者发出通知			System.out.println("老板回来了");			this.getEventHandler().notice();		} catch (Exception e) {						e.printStackTrace();		}			}}

 

/** * 观察者模式实例:利用委托机制对抽象通知者与抽象观察者依赖的解藕。 * 				可指定不同的通知对象和通知时调用不同的方法。 */public class Main {	public static void main(String[] args) {				// 老板(也可以是前台放哨人)		Boss boss = new Boss();				// 看NBA的同事		NBAObserver tongshi1 = new NBAObserver();		// 看股票的同事		StockObserver tongshi2 = new StockObserver();				// 添加被通知的对象		boss.addListener(tongshi1, "closeNBADirectSeeding", new Date());		boss.addListener(tongshi2, "closeStockMarket", "Test");				// 发出通知		boss.notice();	}}

 

运行结果如下:

 

老板回来了关闭NBA直播,继继工作Fri Jun 17 02:44:48 GMT 2011关闭股票行情,继继工作Test

 

转载地址:http://xyxmb.baihongyu.com/

你可能感兴趣的文章
如何使replace方法不区分大小写(转)
查看>>
在双硬盘上安装独立32位和64位双系统(转)
查看>>
MYSQL列类型参考(转)
查看>>
Windows CE .NET 应用程序开发:我有哪些选择?(转)
查看>>
查看ORACLE数据库信息的一些SQL(转)
查看>>
通向Windows CE(转)
查看>>
病毒及木马预警一周播报(06.04.17~04.23)(转)
查看>>
系统安全漏洞扫描绝佳助手之Nmap详解(转)
查看>>
终于以一种奇怪的方式搞定了Oracle的临时表问题(转)
查看>>
数据实时同步或抽取上收的技术分析(转)
查看>>
Pocket PC 实时处理(转)
查看>>
解决WAP中的安全问题(转)
查看>>
超低配置机器无盘网吧的安装方法(转)
查看>>
为 Microsoft Smartphone 开发应用程序(转)
查看>>
一种可以穿透还原卡和还原软件的代码(转)
查看>>
在网吧中如何使用双ADSL线路(转)
查看>>
第五章 WMLScript脚本程序设计(上)(转)
查看>>
何得知Recordset里的记录数(转)
查看>>
蜘蛛:百度收录减少的原因和解决办法(转)
查看>>
ITPUB
查看>>