设计模式之观察者模式

观察者模式介绍

观察者模式:定义对象间的一对多依赖关系,当一个对象的状态发生改变是,所有依赖于他的对象都得到通知并被自动更新。

观察者模式的适用场景:

  1. 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这二者封装在独立的对象中,使他们可以相互独立的改变和和复用。
  2. 对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变。
  3. 一个对象必须通知其他对象,而它又不能假定其他对象是谁,换言之,你不希望这些对象是紧耦合的。

观察者模式的结构:
在这里插入图片描述
观察者模式角色说明:

  • Subject(目标):目标知道它的观察者。可以有任意多个观察者观察同一个目标。同时提供观察者添加和删除的接口。
  • Observer(观察者):为那些在目标发生变化时需要获取通知对象定义的一个接口。
  • ConcreteObserver(具体观察者):实现Observer接口,以使自身状态与目标的状态保持一致。

观察者模式实例

首先来试下观察者接口及实现:

interface Observer {

    void update(Object state);
}

class ObserverImpl1 implements Observer {

    @Override
    public void update(Object state) {
        System.out.println("ObserverImpl1 get event" + state);
    }
}

class ObserverImpl2 implements Observer {

    @Override
    public void update(Object state) {
        System.out.println("ObserverImpl2 get event" + state);
    }
}

subject类实现如下:

class Subject {

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

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

    public void detach(Observer observer) {
        observers.remove(observer);
    }

    public void notify(Object state) {
        for (Observer observer : observers) {
            observer.update(state);
        }
    }
}

测试类:

public static void main(String[] args) {
    Observer observer = new ObserverImpl1();
    Observer observer1 = new ObserverImpl2();

    Subject subject = new Subject();
    subject.attach(observer);
    subject.attach(observer1);

    //发布状态变化
    subject.notify("state change xxx");

    System.out.println("----------------------");
    // 剔除一个观察者
    subject.detach(observer1);

    // 发布状态变化
    subject.notify("state change yyy");
}

观察者模式的优缺点

优点

  1. Subject和Observer之间是松耦合的,分别可以各自独立改变。
  2. Subject在发送广播通知的时候,无需指定具体的Observer,Observer可以自己决定是否要订阅Subject的通知。

缺点

  1. 松耦合导致代码关系不明显,有时可能难以理解。
  2. 如果一个Subject被大量Observer订阅的话,在广播通知的时候可能会有效率问题。

观察者模式在源码中的应用

  1. JDK为我们提供了观察者模式,即Observer和Observable,如下:
public interface Observer {
    void update(Observable o, Object arg);
}
public class Observable {
    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);
        }
    }

    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }

    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();
    }

    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();
    }
}
  1. spring中观察者模式的使用
    熟悉spring的都应该了解,spring有一个多播器,我们在编码时继承一个ApplicationListener接口并注入spring容器,在spring发布事件时,会回调器onApplicationEvent。
class MyApplicationListener implements ApplicationListener {

    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        System.out.println("get application event" + applicationEvent);
    }
}

在spring容器初始时,会将扫描的所有ApplicationListener组件注册到多播器中,而当事件发布时则多播器会将时间发布给没ApplicationListener组件。spring默认多播器为SimpleApplicationEventMuitlcaster,来看一下其multicastEvent方法:

public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
    Executor executor = this.getTaskExecutor();
    Iterator var5 = this.getApplicationListeners(event, type).iterator();
    
    // 获取所有ApplicationListerner并通知
    while(var5.hasNext()) {
        ApplicationListener<?> listener = (ApplicationListener)var5.next();
        if (executor != null) {
            executor.execute(() -> {
                this.invokeListener(listener, event);
            });
        } else {
            this.invokeListener(listener, event);
        }
    }
}

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
    ErrorHandler errorHandler = this.getErrorHandler();
    if (errorHandler != null) {
        try {
            this.doInvokeListener(listener, event);
        } catch (Throwable var5) {
            errorHandler.handleError(var5);
        }
    } else {
        this.doInvokeListener(listener, event);
    }

}

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    try {
        listener.onApplicationEvent(event);
    } catch (ClassCastException var6) {
        String msg = var6.getMessage();
        if (msg != null && !this.matchesClassCastMessage(msg, event.getClass())) {
            throw var6;
        }

        Log logger = LogFactory.getLog(this.getClass());
        if (logger.isTraceEnabled()) {
            logger.trace("Non-matching event type for listener: " + listener, var6);
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值