第十七章 观察者模式
17.1 基本原理
- 观察者模式类似订牛奶业务和发布气象消息等
- 奶站/气象局:Subject
- 用户/第三方网站:Observer
- 观察者模式:对象之间多对一依赖的一种设计方案,被依赖的对象为 Subject,依赖的对象为 Observer,Subject 通知 Observer 变化,比如奶站/气象局是 Subject,是 1 的一方;用户/第三方网站是 Observer,是多的一方。
17.2 角色及职责
- Subject:登记注册、移除和通知
- registerObserver() 注册
- removeObserver() 移除
- notifyObservers() 通知所有的注册的用户(observer),根据不同需求,可以是更新数据,让用户来取,也可能是实施推送,看具体需求定
- Observer:接收输入
- update() 更新
17.3 应用实例
气象站可以将每天测量到的温度、湿度、气压等等以公告的形式发布出去,比如发布到自己的网站或第三方,可以使用观察者模式来实现。
- 观察者模式设计后,会以集合的方式来管理用户(Observer),包括注册、移除和通知。
- 增加观察者(新的公告板/第三方网站),只需要增加一个观察者实现子类,并在客户端调用即可。就不需要去修改核心类 WeatherData 不会修改代码,遵守了 ocp 原则。
//接口, 让WeatherData 来实现
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
//观察者接口,由观察者来实现
public interface Observer {
public void update(float temperature, float pressure, float humidity);
}
// 观察者子类 1
public class CurrentConditions implements Observer {
// 温度,气压,湿度
private float temperature;
private float pressure;
private float humidity;
// 更新 天气情况,是由 WeatherData 来调用,我使用推送模式
public void update(float temperature, float pressure, float humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
display();
}
// 显示
public void display() {
System.out.println("***Today mTemperature: " + temperature + "***");
System.out.println("***Today mPressure: " + pressure + "***");
System.out.println("***Today mHumidity: " + humidity + "***");
}
}
// 观察者子类 2 扩展
public class BaiduSite implements Observer {
// 温度,气压,湿度
private float temperature;
private float pressure;
private float humidity;
// 更新 天气情况,是由 WeatherData 来调用,我使用推送模式
public void update(float temperature, float pressure, float humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
display();
}
// 显示
public void display() {
System.out.println("===百度网站====");
System.out.println("***百度网站 气温 : " + temperature + "***");
System.out.println("***百度网站 气压: " + pressure + "***");
System.out.println("***百度网站 湿度: " + humidity + "***");
}
}
// subject 接口的实现子类,是核心类:
// 1. 包含最新的天气情况信息
// 2. 含有 观察者集合,使用ArrayList管理
// 3. 当数据有更新时,就主动的调用 ArrayList,通知所有的(接入方)就看到最新的信息
public class WeatherData implements Subject {
private float temperatrue;
private float pressure;
private float humidity;
//观察者集合
private ArrayList<Observer> observers;
public WeatherData() {
observers = new ArrayList<Observer>();
}
public float getTemperature() {
return temperatrue;
}
public float getPressure() {
return pressure;
}
public float getHumidity() {
return humidity;
}
public void dataChange() {
//通知所有观察者
notifyObservers();
}
//当数据有更新时,就调用 setData
public void setData(float temperature, float pressure, float humidity) {
this.temperatrue = temperature;
this.pressure = pressure;
this.humidity = humidity;
//调用dataChange, 将最新的信息 推送给 接入方 currentConditions
dataChange();
}
//注册一个观察者
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
//移除一个观察者
@Override
public void removeObserver(Observer o) {
if(observers.contains(o)) {
observers.remove(o);
}
}
//遍历所有的观察者,并通知
@Override
public void notifyObservers() {
for(int i = 0; i < observers.size(); i++) {
observers.get(i).update(this.temperatrue, this.pressure, this.humidity);
}
}
}
// 客户端
public class Client {
public static void main(String[] args) {
//创建一个WeatherData
WeatherData weatherData = new WeatherData();
//创建观察者
CurrentConditions currentConditions = new CurrentConditions();
BaiduSite baiduSite = new BaiduSite(); // 扩展
//注册到weatherData
weatherData.registerObserver(currentConditions);
weatherData.registerObserver(baiduSite); // 扩展
//测试
System.out.println("通知各个注册的观察者, 看看信息");
weatherData.setData(10f, 100f, 30.3f);
}
}
17.4 在 JDK 中的应用
Jdk 的 Observable 类就使用了观察者模式:
- Observable 的作用和地位等价于前面的 Subject
- Observable 是类,不是接口,类中已经实现了核心的方法,即管理 Observer 的方法 add.. delete .. notify...
- Observer 的作用和地位等价于前面的 Observer,有 update 方法
- Observable 和 Observer 的使用方法和前面的一样,只是 Observable 是类,通过继承来实现观察者模式
第十八章 中介者模式
18.1基本介绍
- 中介者模式(Mediator Pattern),用一个中介对象来封装一系列的对象交互。中介者使各个对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
- 中介者模式属于行为型模式,使代码易于维护。
- 比如 MVC 模式,C(Controller 控制器)是 M(Model 模型)和 V(View 视图)的中介者,在前后端交互时起到了中间人的作用。
18.2 角色及职责
- Mediator 是抽象中介者,定义了同事对象到中介者对象的接口
- Colleague 是抽象同事类
- ConcreteMediator 具体的中介者对象,实现 Mediator 中的抽象方法,他需要知道所有的具体的同事类,即以一个集合(HashMap)来管理所有同事类,并接受某个同事对象消息,完成相应的任务
- ConcreteColleague 具体的同事类(会有很多),每个同事只知道自己的行为, 而不了解其他同事类的行为(方法),但是他们都依赖中介者对象
18.3 应用实例
完成智能家庭的项目,各个设备可以协同工作。
- 创建 ConcreteMediator 对象;
- 创建各个同事类对象,比如 Alarm、CoffeeMachine、TV...;
- 在创建同事类对象的时候,就直接通过构造器,加入到 ColleagueMap 中;
- 同事类对象,可以调用 sendMessage方法,最终会去调用 ConcreteMediator 的 getMessage 方法;
- getMessage 会根据接收到的同事对象发出的消息来协调调用其他的同事对象来完成任务;
- 可以看到 getMessage 是核心方法,中介者在这个方法中,协调各个具体的同事对象,根据得到的消息完成相应任务。
18.4注意事项和细节
- 多个类相互耦合,会形成网状结构,使用中介者模式将网状结构分离为星型结构,进行解耦。
- 减少类间依赖,降低了耦合,符合迪米特原则。
- 中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响。
- 如果设计不当,中介者对象本身变得过于复杂,这点在实际使用时,要特别注意。