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);
目录
相关文章
|
6月前
|
设计模式 网络协议 数据可视化
Java 设计模式之状态模式:让对象的行为随状态优雅变化
状态模式通过封装对象的状态,使行为随状态变化而改变。以订单为例,将待支付、已支付等状态独立成类,消除冗长条件判断,提升代码可维护性与扩展性,适用于状态多、转换复杂的场景。
870 157
|
6月前
|
设计模式 Java Spring
Java 设计模式之责任链模式:优雅处理请求的艺术
责任链模式通过构建处理者链,使请求沿链传递直至被处理,实现发送者与接收者的解耦。适用于审批流程、日志处理等多级处理场景,提升系统灵活性与可扩展性。
679 2
|
8月前
|
设计模式 缓存 Java
Java设计模式(二):观察者模式与装饰器模式
本文深入讲解观察者模式与装饰器模式的核心概念及实现方式,涵盖从基础理论到实战应用的全面内容。观察者模式实现对象间松耦合通信,适用于事件通知机制;装饰器模式通过组合方式动态扩展对象功能,避免子类爆炸。文章通过Java示例展示两者在GUI、IO流、Web中间件等场景的应用,并提供常见陷阱与面试高频问题解析,助你写出灵活、可维护的代码。
|
6月前
|
设计模式 算法 搜索推荐
Java 设计模式之策略模式:灵活切换算法的艺术
策略模式通过封装不同算法并实现灵活切换,将算法与使用解耦。以支付为例,微信、支付宝等支付方式作为独立策略,购物车根据选择调用对应支付逻辑,提升代码可维护性与扩展性,避免冗长条件判断,符合开闭原则。
1521 35
|
6月前
|
设计模式 消息中间件 传感器
Java 设计模式之观察者模式:构建松耦合的事件响应系统
观察者模式是Java中常用的行为型设计模式,用于构建松耦合的事件响应系统。当一个对象状态改变时,所有依赖它的观察者将自动收到通知并更新。该模式通过抽象耦合实现发布-订阅机制,广泛应用于GUI事件处理、消息通知、数据监控等场景,具有良好的可扩展性和维护性。
519 8
|
11月前
|
设计模式 缓存 安全
【高薪程序员必看】万字长文拆解Java并发编程!(8):设计模式-享元模式设计指南
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发编程中的经典对象复用设计模式-享元模式,废话不多说让我们直接开始。
228 0
|
8月前
|
设计模式 安全 Java
Java设计模式(一):单例模式与工厂模式
本文详解单例模式与工厂模式的核心实现及应用,涵盖饿汉式、懒汉式、双重检查锁、工厂方法、抽象工厂等设计模式,并结合数据库连接池与支付系统实战案例,助你掌握设计模式精髓,提升代码专业性与可维护性。
|
8月前
|
设计模式 XML 安全
Java枚举(Enum)与设计模式应用
Java枚举不仅是类型安全的常量,还具备面向对象能力,可添加属性与方法,实现接口。通过枚举能优雅实现单例、策略、状态等设计模式,具备线程安全、序列化安全等特性,是编写高效、安全代码的利器。
|
设计模式 存储 供应链
前端必须掌握的设计模式——观察者模式
观察者模式(Observer Pattern)是一种行为型设计模式,实现了一种订阅机制。它包含两个角色:**观察者**(订阅消息、接收通知并执行操作)和**被观察者**(维护观察者列表、发送通知)。两者通过一对多的关系实现解耦,当被观察者状态改变时,会通知所有订阅的观察者。例如,商店老板作为被观察者,记录客户的需求并在商品到货时通知他们。前端应用中,如DOM事件注册、MutationObserver等也体现了这一模式。
|
11月前
|
设计模式 消息中间件 存储
【设计模式】【行为型模式】观察者模式(Observer)
一、入门 什么是观察者模式? 观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会收到通知并自动更新。
468 9