观察者模式

观察者模式应用场景实例

一个典型的购票网站,以购票为核心业务(此模式不限于该业务),但围绕购票会产生不同的其他逻辑,如:

1、购票后记录文本日志
2、购票后记录数据库日志
3、购票后发送短信
4、购票送抵扣卷、兑换卷、积分
5、其他各类活动

传统的解决方案:

在购票逻辑等类内部增加相关代码,完成各种逻辑。

存在问题:

1、一旦某个业务逻辑发生改变,如购票业务中增加其他业务逻辑,需要修改购票核心文件、甚至购票流程。
2、日积月累后,文件冗长,导致后续维护困难。

原因

主要是程序的”紧密耦合”,使用观察模式将目前的业务逻辑优化成”松耦合”,达到易维护、易修改的目的,同时这也符合面向接口编程的思想。

观察者模式概述

观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者observer对象同时监听某一个主题subject对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。

1、观察者模式的优点

观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体,将观察者和被观察者完全隔离

2、观察者模式的缺点

在应用观察者模式时需要考虑一下开发小路问题,程序中包括一个被观察者和多个被观察者,开发和调试比较复杂,
而且Java中的消息的通知默认是顺序执行的,一个观察者的卡顿会影响整体的执行效率。在这种情况下,一般考虑采用异步

案例

1、主题接口
public interface Subject {
    // 注册
    void registerObserver(Observer observer);

    // 发送通知
    void sendMsg(String msg);
}

具体类

public class ConSubject implements Subject {
    // 观察者集合
    private List<Observer> observerList = Lists.newArrayList();

    public void registerObserver(Observer observer) {
        observerList.add(observer);
    }

    // 发送通知
    public void sendMsg(String msg) {
        for (Observer observer : observerList) {
            observer.recvMessage(msg);
        }
    }
}
2、观察者
public interface Observer {
    // 接受主题的消息
    void recvMessage(String msg);
}

观察者可以多个,本文在这里就实现了一个具体观察者

public class AObserver implements Observer {
    private Subject subject;

    AObserver(Subject subject) {
        this.subject = subject;
        subject.registerObserver(this);
    }

    public void recvMessage(String msg) {
        System.out.println("观察者接受主题消息:" + msg);
    }
}
3、测试
public class Test {
    public static void main(String[] args) {
        ConSubject subject = new ConSubject();//主题
        AObserver observer = new AObserver(subject);//观察者
        // 发送消息
        System.out.println("主题发送消息:--");
        subject.sendMsg("Message Content");//主题发生消息
    }
}

执行结果为:

主题发送消息:--
观察者接受主题消息:Message Content

JAVA对观察者模式的内置支持

1、观察者
public interface Observer {

    //每当观察到的对象发生变化时,都会调用此方法
    //o是主题,arg可以是主题传入的消息
    void update(Observable o, Object arg);
}
2、主题

如果单单执行notifyObservers方法,观察者的update方法不会执行,还要调用setChanged(true)方法,允许观察者执行

public class Observable {

    //查询观察者方法是否能执行,默认false不行
    private boolean changed = false;
    
    private Vector<Observer> obs;

    public Observable() {
        obs = new Vector<>();
    }

    //添加观察者,具有排重功能,线程安全
    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }

  
    //给所有观察者发送信息,信息为null
    public void notifyObservers() {
        notifyObservers(null);
    }

    //给所有观察者发送特定的信息
    public void notifyObservers(Object arg) {
        Object[] arrLocal;
        synchronized (this) {
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }

    //清除观察者列表
    public synchronized void deleteObservers() {
        obs.removeAllElements();
    }
    //清除单个观察者
    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }
    
    //设置主题是否改变
    protected synchronized void setChanged() {
        changed = true;
    }

    //清楚改变
    protected synchronized void clearChanged() {
        changed = false;
    }
    //获取改变
    public synchronized boolean hasChanged() {
        return changed;
    }

    //获取观察者个数
    public synchronized int countObservers() {
        return obs.size();
    }
}

你可能感兴趣的:(设计模式)