设计模式——Observer(观察者)

内容摘自《设计模式 可复用面向对象软件的基础》

类型

行为型模式

意图

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

适用性

当出现以下情况时可考虑使用该模式:

  • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将二者独立封装在各自的类中,使其可以独立的改变和复用。
  • 对一个对象的改变必须要同时改变其他对象,而不知道具体有多少对象需要被改变。
  • 一个对象必须通知其他对象,又不能假定其他对象是谁,换言之就是不希望这些对象紧密耦合在一起。

参与者

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

协作

  • 当ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者。
  • 在得到一个具体的改变通知后,ConcreteObserver对象可向目标对象查询信息。ConcreteObserver使用这些信息以使它的状态与目标对象的状态一致。

效果

  • 目标和观察者间的抽象耦合
    对于目标而言,只知道自己有一系列Observer,不知道其具体的类,这使得目标与观察者的耦合变得最小。
  • 支持广播通信
    目标发送的通知,不需要指定它的接收者,只需要通知登记了的观察者对象,目标对象也不感兴趣有多少对象对自己感兴趣,仅有的责任就是通知所有观察者。这带来了在任何时刻增删观察者的自由,如何处理通知,由每一个观察者自己决定。
  • 意外的更新
    因为观察者不知道有其他观察者存在,对于改变目标状态的代价一无所知,这可能会导致其他依赖于目标状态的一系列观察者出现意外的更新,而且难以捕捉。

Demo

假设飞机存在起飞、飞行中、降落三种信号状态,乘客、空乘、地勤人员会关注这些状态,每当状态改变时,三种人员会做出对应的行为。

/**
 * 信号
 */

public abstract class Signal {

    private List<Observer> observers;

    public Signal() {
        this.observers = new ArrayList<Observer>();
    }

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

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

    public void notifyObserver() {
        observers.stream().forEach(o -> {
            o.prepare();
        });
    }
}

/**
 * 飞机指示信号
 */

public class PlaneSignal extends Signal {

    // blue-准备起飞;yellow-准备降落;white-飞行中;
    private String colorSignal;

    public String getColorSignal() {
        return colorSignal;
    }

    public void setColorSignal(String colorSignal) {
        this.colorSignal = colorSignal;
        notifyObserver();
    }

}
public abstract class Observer {

    protected Signal signal;

    public void subscribe(Signal sig) {
        this.signal = sig;
        signal.attach(this);
    }

    public void unSubscribe(Signal sig) {
        sig.detach(this);
    }

    abstract void prepare();
}
/**
 * 乘客
 */

public class Passenger extends Observer {

    @Override
    void prepare() {
        PlaneSignal sig = (PlaneSignal) signal;

        System.out.print("乘客:");
        switch (sig.getColorSignal()) {
        case "blue":
            System.out.println("飞机准备起飞,我要放好行李,绑好安全带");
            break;
        case "yellow":
            System.out.println("飞机准备降落,绑好安全带,确认走时不会忘记行李");
            break;
        default:
            System.out.println("飞机飞行中,打个盹儿吧");
            break;
        }
    }

}
/**
 * 空乘
 */

public class Stewardess extends Observer {

    @Override
    void prepare() {
        PlaneSignal sig = (PlaneSignal) signal;

        System.out.print("空乘:");
        switch (sig.getColorSignal()) {
        case "blue":
            System.out.println("飞机准备起飞,我要提醒乘客关机,绑好安全带");
            break;
        case "yellow":
            System.out.println("飞机准备降落,我要提醒乘客,不要忘记行李");
            break;
        default:
            System.out.println("飞机飞行中,我要去进行派餐服务");
            break;
        }
    }

}
/**
 * 地勤人员
 */

public class GroundStaff extends Observer {

    @Override
    void prepare() {
        PlaneSignal sig = (PlaneSignal) signal;

        System.out.print("地勤:");
        switch (sig.getColorSignal()) {
        case "blue":
            System.out.println("飞机准备起飞,我要快点把托运行李放好");
            break;
        case "yellow":
            System.out.println("飞机准备降落,我要准备接机,运输行李");
            break;
        default:
            System.out.println("飞机飞行中,下一班飞机还有一会,摸个鱼吧");
            break;
        }
    }

}

主程序

public class App {

    public static void main(String[] args) {
        PlaneSignal signal = new PlaneSignal();
        Passenger passenger = new Passenger();
        Stewardess stewardess = new Stewardess();
        GroundStaff groundStaff = new GroundStaff();
        passenger.subscribe(signal);
        stewardess.subscribe(signal);
        groundStaff.subscribe(signal);
        
        System.out.println("--------3个观察者,准备起飞--------");
        signal.setColorSignal("blue");
        
        System.out.println("--------2个观察者,准备降落--------");
        passenger.unSubscribe(signal);
        signal.setColorSignal("yellow");
        
        System.out.println("--------1个观察者,飞行中--------");
        groundStaff.unSubscribe(signal);
        signal.setColorSignal("white");
    }

}

结果为:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章