观察者模式
定义:(观察者--观察目标)对象之前的一对多的依赖关系,是的每当一个对象状态发生改变的时候,其他相关依赖对象都可以收到通知并且更新。(也可以叫发布-订阅)模式。
1.代码案例
在等红绿灯中,多辆汽车在等待红灯变绿,当红灯变绿是,所有等待的汽车都开始启动。
红灯变绿→发送通知信息→汽车做出响应
ControlCenter 充当抽象目标类
package com.company.Demo.observer;
import java.util.ArrayList;
import java.util.List;
public abstract class ControlCenter {
// 汽车
protected List<Observer> play = new ArrayList<>();
// 加入排队汽车
public void join(Observer obs) {
System.out.println(obs.getCarName() + "进入排队!");
play.add(obs);
}
public abstract void notifyObserver();
}
TrafficLightControlCenter 具体指挥部类,充当具体红路灯目标类
package com.company.Demo.observer;
import java.util.concurrent.TimeUnit;
public class TrafficLightControlCenter extends ControlCenter {
Integer time;
public TrafficLightControlCenter(Integer time) {
this.time=time;
System.out.printf("--------红灯时间%s秒---------%n", time);
}
@Override
public void notifyObserver() {
for (Observer observer : play) {
while (true) {
if (time <= 0) {
observer.start();
break;
} else {
System.out.printf("---------红灯倒计时%s---------%n", time);
try {
// 模拟倒计时
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
time--;
}
}
}
}
Observer 抽象观察者
package com.company.Demo.observer;
public interface Observer {
String getCarName();
// 发动汽车
void start();
// 根据红绿灯变化通知
void detecting(ControlCenter acc);
}
Car 具体实现观察者类
package com.company.Demo.observer;
public class Car implements Observer {
private String name;
public Car(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String getCarName() {
return getName();
}
@Override
public void start() {
System.out.println(this.name + "发动汽车");
}
@Override
public void detecting(ControlCenter acc) {
acc.notifyObserver();
}
}
测试类
package com.company.Demo.observer;
public class Main {
public static void main(String[] args) {
ControlCenter ally=new TrafficLightControlCenter(5);
Observer obs=new Car("大众cc");
ally.join(obs);
Observer obs2=new Car("宝马M3");
ally.join(obs2);
Observer obs3=new Car("桑塔纳");
ally.join(obs3);
// 状态通知
obs.detecting(ally);
}
}
结果;
--------红灯时间5秒---------
大众cc进入排队!
宝马M3进入排队!
桑塔纳进入排队!
---------红灯倒计时5---------
---------红灯倒计时4---------
---------红灯倒计时3---------
---------红灯倒计时2---------
---------红灯倒计时1---------
大众cc发动汽车
宝马M3发动汽车
桑塔纳发动汽车
car.detecting() → ControlCenter.notifyObserver() → car.start()
2.JDK 对观察者模式的支持
public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
* method.
*/
void update(Observable o, Object arg);
}
public class Observable {....}
使用JDK自带实现观察者模式
Car 是观察者
package com.company.Demo.observer.jdk;
import java.util.Observable;
import java.util.Observer;
public class Car implements Observer {
private String name;
public Car(String name) {
this.name = name;
}
public void start() {
System.out.println(this.name + "发动汽车");
}
@Override
public void update(Observable o, Object arg) {
start();
}
}
TrafficLightControlCenter 是被观察者
package com.company.Demo.observer.jdk;
import java.util.Observable;
public class TrafficLightControlCenter extends Observable {
public void end(){
System.out.println("------红灯结束-----");
super.setChanged();
super.notifyObservers();
}
}
验证:
package com.company.Demo.observer;
import com.company.Demo.observer.jdk.Car;
import com.company.Demo.observer.jdk.TrafficLightControlCenter;
public class Main {
public static void main(String[] args) {
Car car=new Car("大众cc");
TrafficLightControlCenter call=new TrafficLightControlCenter();
call.addObserver(car);
call.end();
}
}
结果:
------红灯结束-----
大众cc发动汽车
3.观察者模式的优点
1.可以实现表示层和数据逻辑层的分离,定义了稳定的消息更新传递机制,并且抽象了更新接口,使得可以有各种各样不同的表示层充当具体观察者角色
2.在观察目标和观察者直接建立一个抽象的耦合,观察目标只需要维持一个抽象观察者的集合,无须了解具体观察者,由于观察目标和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。
3.支持广播通信,观察目标会向所有已注册的观察者对象发送通知,简化了一对多关系的系统设计难度
4.符合开闭原则,增加新的具体观察者无须修改原有代码。
4.观察者模式的缺点
1.如果在观察者和观察目标之间存在循环依赖,观察目标会触发它们之间进行循环调用,可能导致系统崩溃
2.如果一个观察目标对象有很多直接和间接观察者,将所有观察者都通知到会花费很多时间
3.观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的
5.观察者模式适应环境
1.一个对象改变将导致一个或者多个其他对象也发生改变,而且并不知道具体多少对象将发生改变,也不知道这些对象是谁
2.需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象行为将影响C对象,可以使用观察者模式创建一种链式触发机制