java 观察者模式利与弊分析

观察者模式是比较常用的一种设计模式,观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监听一个主题对象。当被观察者状态发生改变时通知相应的观察者,使得这些观察者对象能够自动更新。但当我们使用这种模式时需要进行利弊权衡,观察者模式并不像我们想象中的那么简单。

观察者模式简例

抽象主题(Subject)角色
抽象主题角色把所有对观察者对象的引用保存在一个聚集(比如ArrayList对象)里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,抽象主题角色又叫做抽象被观察者(Observable)角色。

具体主题(SubjectConcrete)角色
将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者(Concrete Observable)角色。

抽象观察者(Observer)角色
为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口。

具体观察者(ObserverConcrete)角色
存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体观察者角色可以保持一个指向具体主题对象的引用。

观察者模式代码

Subject类是被观察者的抽象类,其中提供了可以让继承该类的所有被观察者能够调用的方法,其中维护一个ArrayList用来存放观察者,用changed来标记是否发生了变化应该通知所有的观察者。

package ObserversEx;

import java.util.*;

public class Subject {

    private boolean changed;

    private ArrayList<Observer> observers = new ArrayList<Observer>();

    protected synchronized void setChange() {
        changed = true;
    }

    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    public void changeObservers(String data) {
        int size = 0;
        Observer[] arrays = null;
        synchronized (this) {
            if (changed) {
                clearChanged();
                size = observers.size();
                arrays = new Observer[size];
                observers.toArray(arrays);
            }
        }
        if (arrays != null) {
            for (Observer observer : arrays) {
                observer.update(this, data);
            }
        }
    }

    protected synchronized void clearChanged() {
        // TODO Auto-generated method stub
        changed = false;
    }

}

SubjectConcrete类是具体的被观察者类,其他的方法已经在父类中有所实现,具体的被观察者类只需要实现change方法,决定具体在状态发生变化的时候应该怎样处理即可。

package ObserversEx;

public class SubjectConcrete extends Subject {

    public synchronized void change(String state) {
        setChange();
        changeObservers(state);
    }

}

Observer类是所有观察者的父类,其中包含了观察者所必须的update类,在接收到被观察者状态的改变后,被观察者subject通过在ArrayList中轮询调用update方法来更新观察者。update方法传入一个被观察者对象,用来获取其中的信息,传入一个String表示更新后的状态。

package ObserversEx;

public class Observer {

    public void update(Subject subject, String data) {
    }

}

ObserverConcrete类是具体的观察者类,其中只需要实现update的具体方法即可。在示例代码中我们仅让他在控制台输出一句话。

package ObserversEx;

public class ObserverConcrete extends Observer {

    public void update(Subject subject, String data) {
        System.out.println("Message is " + data);
    }

}

Main主类,在主类中创建观察者和被观察者,将观察者通过add方法添加到被观察者的列表中,再改变被观察者的状态,发现控制台有输出,表示观察者已经发现了被观察者的变化,并且调用了update方法进行了更新。

package ObserversEx;

public class Main {

    public static void main(String[] args) {

        SubjectConcrete subject = new SubjectConcrete();
        Observer observer = new ObserverConcrete();
        subject.addObserver(observer);
        subject.change("new state");

    }

}

观察者模式优势分析

1.观察者模式符合松耦合

通过一个列表来维护观察者,这使得被观察者无需在意观察者的具体类型,只需要发送消息进行通知即可,通过调用update方法,观察者也无须关系被观察者的情况,只当有状态改变时进行更新即可。观察者增加或删除无需修改主题的代码,只需调用主题对应的增加或者删除的方法即可。

2.观察者不会因主动获取通知而错过状态

由于被动接受,正常情况下不会错过主题的改变通知。而主动获取的话,由于时机选取问题,可能导致错过某些状态。

3.表示层和数据逻辑层的分离

观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。观察者模式在观察目标和观察者之间建立一个抽象的耦合。观察者模式支持广播通信。观察者模式符合“开闭原则”的要求。

观察者模式劣势分析

1.通知观察者的时间花费

如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。

2.多个被通知者间循环可能发生死锁

如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

3.内存问题

主题持有观察者的引用,如果未正常处理从主题中删除观察者,会导致观察者无法被回收。
如果观察者具体实现代码有问题,会导致主题和观察者对象形成循环引用,在某些采用引用计数的垃圾回收器可能导致无法回收。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值