TypechoJoeTheme

IT技术分享

统计

观察者模式(Observer)——23种设计模式之行为型模式

2015-06-28
/
0 评论
/
509 阅读
/
正在检测是否收录...
06/28

在软件构建过程中,我们需要为某些对象建立 一种“通知依赖关系”------一个对象(目标对象) 的状态发生改变,所有的依赖对象(观察者对象) 都将得到通知。如果这样的依赖关系过于紧密, 将使软件不能很好地抵御变化。

观察者定义了对象间一对多的关系,当一个对象的状态变化时,所有依赖它的对象都得到通知并且自动地更新。

观察者模式又叫发布订阅模式,是对象之间多对一依赖的一种实际方案,被依赖的对象为Subject,依赖的对象为Observer。多个观察者同时监听一个主题对象,当主题对象发生变化时,就会通知所有的观察者对象,使得他们能够自动更新。

一、类图表示

观察者模式涉及到Subject(目标),Observer(观察者),ConcreteSubject(具体目标),ConcreteObserver(具体观察者)等角色

  • ①、Subject(目标):目标知道它的观察者。可以有任意多个观察者观察同一个目标。提供注册和删除观察者对象的接口。
  • ②、Observer(观察者):为那些在目标发生改变时需获得通知的对象定义一个更新接口。
  • ③、ConcreteSubject(具体目标):将有关状态存入各ConcreteObserver对象。当它的状态发生改变时, 向它的各个观察者发出通知。
  • ④、ConcreteObserver(具体观察者):维护一个指向ConcreteSubject对象的引用。存储有关状态,这些状态应与目标的状态保持一致。实现Observer的更新接口以使自身状态与目标的状态保持一致。

java-observer-model-1

二、代码示例

public interface Subject {

    //methods to register and unregister observers

    public void register(Observer obj);
    public void unregister(Observer obj);

    //method to notify observers of change
    public void notifyObservers();

    //method to get updates from subject
    public Object getUpdate(Observer obj);

}
public interface Observer {

    //method to update the observer, used by subject
    public void update();

    //attach with subject to observe
    public void setSubject(Subject sub);
}
public class MyTopic implements Subject {

    private List<Observer> observers;
    private String message;
    private boolean changed;
    private final Object MUTEX= new Object();

    public MyTopic(){
        this.observers=new ArrayList<>();
    }
    @Override
    public void register(Observer obj) {
        if(obj == null) throw new NullPointerException("Null Observer");
        if(!observers.contains(obj)) observers.add(obj);
    }

    @Override
    public void unregister(Observer obj) {
        observers.remove(obj);
    }

    @Override
    public void notifyObservers() {
        List<Observer> observersLocal = null;
        //synchronization is used to make sure any observer registered after message is received is not notified
        synchronized (MUTEX) {
            if (!changed)
                return;
            observersLocal = new ArrayList<>(this.observers);
            this.changed=false;
        }
        for (Observer obj : observersLocal) {
            obj.update();
        }

    }

    @Override
    public Object getUpdate(Observer obj) {
        return this.message;
    }

    //method to post message to the topic
    public void postMessage(String msg){
        System.out.println("Message Posted to Topic:"+msg);
        this.message=msg;
        this.changed=true;
        notifyObservers();
    }

}
public class MyTopicSubscriber implements Observer {

    private String name;
    private Subject topic;

    public MyTopicSubscriber(String nm){
        this.name=nm;
    }
    @Override
    public void update() {
        String msg = (String) topic.getUpdate(this);
        if(msg == null){
            System.out.println(name+":: No new message");
        }else
            System.out.println(name+":: Consuming message::"+msg);
    }

    @Override
    public void setSubject(Subject sub) {
        this.topic=sub;
    }

}
public class ObserverPatternTest {

    public static void main(String[] args) {
        //create subject
        MyTopic topic = new MyTopic();

        //create observers
        Observer obj1 = new MyTopicSubscriber("Obj1");
        Observer obj2 = new MyTopicSubscriber("Obj2");
        Observer obj3 = new MyTopicSubscriber("Obj3");

        //register observers to the subject
        topic.register(obj1);
        topic.register(obj2);
        topic.register(obj3);

        //attach observer to subject
        obj1.setSubject(topic);
        obj2.setSubject(topic);
        obj3.setSubject(topic);

        //check if any update is available
        obj1.update();

        //now send message to subject
        topic.postMessage("New Message");
    }

}

三、模式分析

观察者模式描述了如何建立这种关系

  • ①、模式中的关键对象是目标(subject)和观察者(observer)。
  • ②、一个目标可有任意数目的依赖它的观察者。一旦目标的状态发生改变,所有的观察者都得到通知。
  • ③、作为对该通知的响应,每个观察者都将查询目标以使其状态与目标的状态同步。

四、设计原则分析

1、符合OCP原则

使用该模式的动机就是为了在增加新 的观察对象时可以无需更改被观察的对象。即保持被 观察对象封闭。

2、符合LSP原则

MyTopic可以替换Subject , MyTopicSubscriber可以替换Observer。

3、符合DIP原则

Observer是一个抽象类,具体的 MyTopicSubscriber依赖于它, Subject是不应被实例化的类, 其具体方法也依赖于Observer。

五、模式类型

1、拉模型

  • ①、优点是实现比较简单,而且Subject 类和Observer 类可以成为库中的标准可重用元素。
  • ②、当调用MyTopicSubscriber的update()方法时, MyTopicSubscriber从MyTopic中”拉出”消息并显示它,很方便。
  • ③、但如果你正观察一个具有一千个字段的雇员记录,刚好收到一个更新,这时不知道哪个字段发生了变化?
  • ④、如果被观察的对象比较简单,那么拉模型就很合 适。

2、推模型

  • ①、推模型的Observer模式可以为上述问题提供帮助。
  • ②、notify方法和update方法都带有一个参数,该参数是一个 提示。
  • ③、如果被观察者对象比较复杂,并且观察者需要一 个提示,那么推模型合适

六、优缺点分析

1、优点

  • ①、Subject和Observers的抽象耦合:Subject只知道 它有一系列的Observers,每个符合抽象的 Observer类的简单接口,但是不知道具体类型
  • ②、支持广播通信:Subject对象不关心到底有多少对象对自己感兴趣,其唯一责任是通知它的各观察者。

2、缺点

  • ①、一个观察者不知道其它观察者的存在,出现意外的更新时,难以捕捉错误

七、应用场景

当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变。

  • ①、当一个抽象模型有两个方面, 其中一个方面依赖 于另一方面。将这二者封装在独立的对象中以 使它们可以各自独立地改变和复用。
  • ②、当一个对象必须通知其它对象,而又不能假定其它对象是谁。换言之,你不希望这些对象是紧密耦合的。
  • ③、有的东西变化或者发生某件事情的时候,可能引发其他一些对象的行为。或者说,有些对象作为观察者在始终盯着某个对象,一旦有事发生就需要立即行动。

八、总结

观察者定义了对象间一对多的关系,当一个对象的状态变化时,所有依赖它的对象都得到通知并且自动地更新。

  • ①、这一模式中的关键对象是目标(subject)和观察者 (observer)。一个目标可以有任意数目的依赖它的观察 者。一旦目标的状态发生改变, 所有的观察者都得到 通知。作为对这个通知的响应,每个观察者都将查询 目标以使其状态与目标的状态同步。
  • ②、发出改变请求的Observer对象并不立即更新,而是 将其推迟到它从目标得到一个通知之后。Notify不总是由 目标对象调用。它也可被一个观察者或其它对象调用
朗读
赞 · 0
版权属于:

IT技术分享

本文链接:

https://idunso.com/archives/445/(转载时请注明本文出处及文章链接)