java-设计模式-观察者模式

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

简单观察者模式

观察者模式中,一个被观察者管理所有依赖它的观察者,并且在本身的状态改变时主动发出通知。这通常通过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。
角色
抽象被观察者角色:把所有对观察者对象的引用保存在一个集合中,每个被观察者角色都可以有任意数量的观察者。被观察者提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
具体被观察者角色:在被观察者内部状态改变时,给所有登记过的观察者发出通知。具体被观察者角色通常用一个子类实现。
具体观察者角色:该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。通常用一个子类实现。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。
适用场景
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<Watcher> list = new ArrayList<Watcher>();  

     @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<Observer> observers = new ArrayList<Observer>();

    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);
目录
相关文章
|
23天前
|
设计模式 监控 Java
Kotlin - 改良设计模式 - 观察者模式
Kotlin - 改良设计模式 - 观察者模式
44 3
|
1月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
|
2月前
|
设计模式 传感器
【设计模式】观察者模式(定义 | 特点 | Demo入门讲解)
【设计模式】观察者模式(定义 | 特点 | Demo入门讲解)
44 0
|
12天前
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
|
14天前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
32 1
|
22天前
|
设计模式 Java 数据库连接
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
29 4
|
1月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
27 3
|
2月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
35 9
|
2月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
34 2
|
2月前
|
设计模式 Java 程序员
[Java]23种设计模式
本文介绍了设计模式的概念及其七大原则,强调了设计模式在提高代码重用性、可读性、可扩展性和可靠性方面的作用。文章还简要概述了23种设计模式,并提供了进一步学习的资源链接。
49 0
[Java]23种设计模式