《一天一模式》— 观察者模式

一、观察者模式的概念

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

二、什么时候使用观察者模式

当一个对象被修改,或者发生某些变化时,需要自动通知依赖它的一些对象,则可以使用观察者模式。

例如:当汽车熄火时,需要更新汽车的定位、发送熄火的通知、生成本次的行程,就可以使用观察者模式,这个例子中发生变化的位置是熄火,那么发生熄火需要通知依赖它的一些对象,就是定位、通知和行程。

下面来看看,如何用Java语言实现观察者模式。

三、怎么使用观察者模式

3.1 不适用观察者模式的弊端

用上面说的业务场景为例,如果不使用观察者模式来实现,可以看下面的伪代码:

public class EngineOffEvent() {

    public void engineOff() {
        Location localtion = new Localtion();
        Notification notification = new Notification();
        Trip trip = new Trip();

        localtion.update();
        notification.notify();
        trip.createTrip();
    }
}

这种做法有如下两个主要弊端:

耦合度高:可以看到EngineOffEvent类耦合了所有其他的业务类,造成维护困难; 扩展性差:当需要在熄火时做新业务时,需要修改engineOff方法内的代码,违反了开闭原则; 灵活度低:不能控制通知的对象个数;

3.2 如何用观察者模式解决问题

根据上面的需求,用观察者模式进行设计,下面看看类图和代码:

代码如下:

/**
 * 观察者接口。
 * */
public interface Observer {
    /**
     * 当气象监测数据改变时,主题会把这些状态值当作方法的参数,传送给观察者。
     * */
    void update(String data);
}

public class LocaltionObserver implements Observer{
    public void update(String data) {
        System.out.println(data + ":更新位置。");
    }
}

public class NotificationObserver implements Observer{
    public void update(String data) {
        System.out.println(data + ":发送通知。");
    }
}

public class TripObserver implements Observer {
    public void update(String data) {
        System.out.println(data + ":生成行程。");
    }
}

/**
 * 主题接口。
 * */
public interface Subject {
    /**
     * registerObserver和removeObserver方法都需要一个观察者作为变量,该观察者是用来注册或被删除的。
     * */
    void registerObserver(Observer ob);

    void removeObserver(Observer ob);

    /**
     * 当主题的状态改变时,这个方法会被调用,已通知所有的观察者。
     * */
    void notifyObservers(String data);

}

// 熄火事件
public class EngineOffEvent implements Subject {

    // 观察者对象集合
    private List<Observer> observers;

    public EngineOffEvent() {
        observers = new ArrayList<Observer>();
    }

    // 注册观察者
    public void registerObserver(Observer ob) {
        observers.add(ob);
    }

    // 移除观察者
    public void removeObserver(Observer ob) {
        int index = observers.indexOf(ob);
        if (index >= 0)
            observers.remove(index);
    }

    // 发生变化进行通知
    public void notifyObservers(String data) {
        // 通知全部观察者
        for (Observer ob : observers) {
            ob.update(data);
        }
    }

}

// 使用
public class Client {

    public static void main(String[] args) {
        Subject subject = new EngineOffEvent();
        subject.registerObserver(new LocaltionObserver());
        subject.registerObserver(new NotificationObserver());
        subject.registerObserver(new TripObserver());
        subject.notifyObservers("京A88888熄火");
    }

}

//京A88888熄火:更新位置。
//京A88888熄火:发送通知。
//京A88888熄火:生成行程。

观察者模式主要分为两部分:

Subject,主题,是发生变化的那个对象,例子中是熄火事件; Observer,观察者,是发生变化后需要通知的多个对象,例子中是通知、位置和行程;

在使用时,可以动态添加或者删除观察者,灵活配置。

3.3 观察者模式的好处

耦合度低:解除了3.1小节中,EngineOffEvent类与其他的业务类的耦合; 扩展性高:当需要在熄火时做新业务时,创建一个新对象实现Observer,然后注册到Subject即可; 灵活度高:可以随意添加或移除Observer;

3.4 其他可以注意的地方

Java内置了观察者模式:

java.util.Observable(类)

java.util.Observer(接口)

可以使用内置的观察者,但是其中Observable对应的是上面例子中的Subject,他是一个Class而不是Interface,如果使用内置的接口,则需要把宝贵继承机会用掉,若你的类已经使用了继承关系,则无法使用。

四、总结

上面的观察者模式,从代码上来说,就是面相接口编程,在Subject中有一个List<Observer>,在发生变化后,循环调用List中的对象的方法,确保都通知到,并且可以对List进行添加和删除。

从业务上来说,当发生某个事件后,需要批量通知许多个对象。则可以使用这个模式。

以上就是我对观察者模式的一些理解,有不足之处请大家指出,谢谢。

栏目