“内容摘自《设计模式 可复用面向对象软件的基础》
类型
行为型模式
意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
适用性
当出现以下情况时可考虑使用该模式:
-
一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将二者独立封装在各自的类中,使其可以独立的改变和复用。 -
对一个对象的改变必须要同时改变其他对象,而不知道具体有多少对象需要被改变。 -
一个对象必须通知其他对象,又不能假定其他对象是谁,换言之就是不希望这些对象紧密耦合在一起。
参与者
-
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");
}
}
结果为: