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

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

简单观察者模式

观察者模式中,一个被观察者管理所有依赖它的观察者,并且在本身的状态改变时主动发出通知。这通常通过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

角色
抽象被观察者角色:把所有对观察者对象的引用保存在一个集合中,每个被观察者角色都可以有任意数量的观察者。被观察者提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
具体被观察者角色:在被观察者内部状态改变时,给所有登记过的观察者发出通知。具体被观察者角色通常用一个子类实现。
具体观察者角色:该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。通常用一个子类实现。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。
适用场景
1) 当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
2) 当对一个对象的改变需要同时改变其它对象, 而不知道具体有多少对象有待改变。
3) 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的

public interface Watcher  {       public void update();  }
public interface Watched  {       public void addWatcher(Watcher watcher);       public void removeWatcher(Watcher watcher);       public void notifyWatchers();  }
public class Thief implements Watcher  {
@Override public void update() { System.out.println(“运输车有行动,强盗准备动手"); } }
public class Police implements Watcher  {
@Override public void update() { System.out.println(“运输车有行动,警察护航"); } }
public class Transporter implements Watched  {
private List
list = new ArrayList
(); @Override public void addWatcher(Watcher watcher) { list.add(watcher); } @Override public void removeWatcher(Watcher watcher) { list.remove(watcher); } @Override public void notifyWatchers(String str) { for (Watcher watcher : list) { watcher.update(); } } }
[java] view plain copy print?在CODE上查看代码片派生到我的代码片public class Test  {       public static void main(String[] args)       {            Transporter transporter = new Transporter();            Police police = new Police();            Security security = new Security();            Thief thief = new Thief();            transporter.addWatcher(police);            transporter.addWatcher(security);            transporter.addWatcher(security);            transporter.notifyWatchers();       }  }

推模型和拉模型

在观察者模式中,又分为推模型和拉模型两种方式。
  ●  推模型
     主题对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。
  ●  拉模型
     主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取,相当于是观察者从主题对象中拉数据。一般这种模型的实现中,会把主题对象自身通过update()方法传递给观察者,这样在观察者需要获取数据的时候,就可以通过这个引用来获取了。

最近做一个消息系统,其中涉及到新消息数的即时更新,当时就想到了观察者模式,后来听同事提到推拉模式,感觉推模式原理上应该还是属于观察者模式,只不过把server变成了被观察对象,client被动观察 .

其实推拉模式我们经常遇到,如广播(推)、HTTP请求(拉),只是没有刻意去追求概念。设计时还是应该多考虑到。
考虑到性能还效率,最终还是选择了拉模式,每隔一断时间请求一次、更新。

下面是引用:

推(push)模式是一种基于客户器/服务器机制、由服务器主动将信息送到客户器的技术。在push模式应用中,服务器把信息送给客户器之前,并没有明显的客户请求。push事务由服务器发起。push模式可以让信息主动、快速地寻找用户/客户器,信息的主动性和实时性比较好。但精确性较差,可能推送的信息并不一定满足客户的需求。推送模式不能保证能把信息送到客户器,因为推模式采用了广播机制,如果客户器正好联网并且和服务器在同一个频道上,推送模式才是有效的。push模式无法跟踪状态,采用了开环控制模式,没有用户反馈信息。在实际应用中,由客户器向服务器发送一个申请,并把自己的地址(如IP、port)告知服务器,然后服务器就源源不断地把信息推送到指定地址。在多媒体信息广播中也采用了推模式。另外,如手机*、qq广播。

拉(pull)模式与推模式相反,是由客户器主动发起的事务。服务器把自己所拥有的信息放在指定地址(如IP、port),客户器向指定地址发送请求,把自己需要的资源“拉”回来。不仅可以准确获取自己需要的资源,还可以及时把客户端的状态反馈给服务器。

使用jdk的java.util.Observable

import java.util.Observable;/** * 天气目标的具体实现类 * @author lenovo * */public class ConcreatWeatherSubject extends Observable{
private String content; public String getContent() { return content; } public void setContent(String content) { this.content = content; //通知所有的观察者 this.setChanged(); //推模型:主动通知 this.notifyObservers(content); //this.notifyObservers(); }}
import java.util.Observable;import java.util.Observer;public class ConcreatObserver implements Observer {
private String observerName; public String getObserverName() { return observerName; } public void setObserverName(String observerName) { this.observerName = observerName; } /** * Observable o 拉取方式 * Object arg 推的方式,推具体的内容过来 */ @Override public void update(Observable o, Object arg) { System.out.println(this.observerName+"收到推送消息:"+arg); System.out.println(this.observerName+"拉去消息中的内容:"+((ConcreatWeatherSubject)o).getContent()); }}
public class Client {    public static void main(String[] args) {        ConcreatWeatherSubject subject= new ConcreatWeatherSubject();        ConcreatObserver girl = new ConcreatObserver();        girl.setObserverName("king");        ConcreatObserver girl1 = new ConcreatObserver();        girl1.setObserverName("jinhang");        ConcreatObserver girl2 = new ConcreatObserver();        girl2.setObserverName("kee");        subject.addObserver(girl1);        subject.addObserver(girl);        subject.addObserver(girl2);        subject.setContent("天气晴朗!");    }}

条件消息系统

import java.util.ArrayList;import java.util.List;public abstract class WeatherSubject {
public List
observers = new ArrayList
(); public void attach(Observer o) { observers.add(o); } public void dettach(Observer o) { observers.remove(o); } protected abstract void notifyObservers();}
import java.util.Iterator;public class Subject1 extends WeatherSubject{
private String weatherContent; public String getWeatherContent() { return weatherContent; } public void setWeatherContent(String weatherContent) { this.weatherContent = weatherContent; this.notifyObservers(); } @Override protected void notifyObservers() { for(Observer o: observers){ //通知条件 if("下雨".equals(this.weatherContent)){ System.out.println("notifyObservers"); if("jinhang".equals(o.getObserverName())){ o.update(this); } if("kee".equals(o.getObserverName())){ o.update(this); } } if("下雪".equals(this.weatherContent)){ if("king".equals(o.getObserverName())){ o.update(this); } } } }}
public interface Observer {    public void update(WeatherSubject subject);    public void setObserverName(String observerName);    public String getObserverName();}
public class Observer1 implements Observer{
private String observerName; private String weatherContent; private String remindContet; public String getWeatherContent() { return weatherContent; } public void setWeatherContent(String weatherContent) { this.weatherContent = weatherContent; } public String getRemindContet() { return remindContet; } public void setRemindContet(String remindContet) { this.remindContet = remindContet; } @Override public void update(WeatherSubject subject) { System.out.println("start..............."); weatherContent = ((Subject1)subject).getWeatherContent(); System.out.println(observerName+"收到消息"+weatherContent+"准备去:"+remindContet); } @Override public void setObserverName(String observerName) { this.observerName = observerName; } @Override public String getObserverName() { return observerName; }}
public class Test {    public static void main(String[] args) {        Subject1 subject1 = new Subject1();        Observer1 observer1 = new Observer1();        Observer1 observer2 = new Observer1();        observer1.setObserverName("jinhang");        observer1.setRemindContet("购物");        observer2.setObserverName("kee");        observer2.setRemindContet("不出去了");        subject1.attach(observer1);        subject1.attach(observer2);        subject1.setWeatherContent("下雨");    }}

JUnit为用户提供了三种不同的测试结果显示界面,以后还可能会有其它方式的现实界面……。怎么才能将测试的业务逻辑和显示结果的界面很好的分离开?不用问,就是观察者模式!

public interface TestListener {
/** * An error occurred. */ public void addError(Test test, Throwable t); /** * A failure occurred. */ public void addFailure(Test test, AssertionFailedError t); /** * A test ended. */ public void endTest(Test test); /** * A test started. */ public void startTest(Test test);}
//具体观察者角色,我们采用最简单的TextUI下的情况来说明(AWT,Swing对于整天做Web应用的人来说,已经很陌生了)public class ResultPrinter implements TestListener {
//省略好多啊,主要是显示代码…… //下面就是实现接口TestListener的四个方法 //填充方法的行为很简单的说 /** * @see junit.framework.TestListener#addError(Test, Throwable) */ public void addError(Test test, Throwable t) { getWriter().print("E"); } /** * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError) */ public void addFailure(Test test, AssertionFailedError t) { getWriter().print("F"); } /** * @see junit.framework.TestListener#endTest(Test) */ public void endTest(Test test) { } /** * @see junit.framework.TestListener#startTest(Test) */ public void startTest(Test test) { getWriter().print("."); if (fColumn++ >= 40) { getWriter().println(); fColumn= 0; } }}来看下我们的目标角色,随便说下,由于JUnit功能的简单,只有一个目标——TestResult,因此JUnit只有一个具体目标角色。//好长的代码,好像没有重点。去掉了大部分与主题无关的信息//下面只列出了当Failures发生时是怎么来通知观察者的public class TestResult extends Object {
//这个是用来存放测试Failures的集合protected Vector fFailures;//这个就是用来存放注册进来的观察者的集合 protected Vector fListeners; public TestResult() { fFailures= new Vector(); fListeners= new Vector(); } /** * Adds a failure to the list of failures. The passed in exception * caused the failure. */ public synchronized void addFailure(Test test, AssertionFailedError t) { fFailures.addElement(new TestFailure(test, t)); //下面就是通知各个观察者的addFailure方法 for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { ((TestListener)e.nextElement()).addFailure(test, t); } } /** * 注册一个观察者 */ public synchronized void addListener(TestListener listener) { fListeners.addElement(listener); } /** * 删除一个观察者 */ public synchronized void removeListener(TestListener listener) { fListeners.removeElement(listener); } /** * 返回一个观察者集合的拷贝,当然是为了防止对观察者集合的非法方式操作了 * 可以看到所有使用观察者集合的地方都通过它 */ private synchronized Vector cloneListeners() { return (Vector)fListeners.clone(); } ……}
察者模式组成所需要的角色在这里已经全了。不过好像还是缺点什么……。呵呵,对!就是它们之间还没有真正的建立联系。在JUnit中是通过TestRunner来作的,而你在具体的系统中可以灵活掌握。看一下TestRunner中的代码:public class TestRunner extends BaseTestRunner {
private ResultPrinter fPrinter;public TestResult doRun(Test suite, boolean wait) {//就是在这里注册的 result.addListener(fPrinter);

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

你可能感兴趣的文章
洛谷P1345 [USACO5.4]奶牛的电信Telecowmunication(最小割)
查看>>
洛谷P3396 哈希冲突(分块)
查看>>
优化Mysql数据库的8个方法
查看>>
Centos7下用户登录失败N次后锁定用户禁止登陆的方法
查看>>
开源许可协议简介
查看>>
程序性能优化的3个级别
查看>>
有的日期输入框,可直接调用javascripts
查看>>
手工创建表控制条目
查看>>
poj 2109 -- Power of Cryptography
查看>>
通过Navicat for MySQL远程连接的时候报错mysql 1130的解决方法
查看>>
Hive函数&压缩
查看>>
timestamp与timedelta,管理信息系统概念与基础
查看>>
JVM必读----------垃圾收集器详解
查看>>
好多问题
查看>>
重写对象ToString方法
查看>>
备忘: C++中的 vector 容器
查看>>
smt中查看图片与视频缩略图中,如何获得小视频的长度。
查看>>
图片(img标签)的onerror事件
查看>>
2013应届毕业生“百度”校招应聘总结
查看>>
CentOS系统启动流程
查看>>