观察者
天气预报项目需求 具体要求如下:
-
气象站可以公告每天测量的温度、湿度、气压等。 发布到自己的网站或第三方)。
-
开放式需要设计API,便于其他第三方也能接入气象站获取数据。
-
接口提供温度、压力和湿度
-
测量数据更新时,应能够实时通知第三方
-
通过getXxx该方法允许第三方访问并获取相关信息.
-
当数据更新时,气象站调用dataChange() 当第三方再次获得更新数据时 当然,最新的数据也可以通过取时来推送。
WeatherData维修:新浪,自己的公告板对象。
- 然后调用这些对象dataChange(),即:推送
非模式
自己的网站
/** * 显示当前天气状况(可理解为气象站本身的网站) */ public class CurrentConditions {
// 温度、气压、湿度 private float temperature; private float pressure; private float humidity; //更新 天气条件,是由 WeatherData 我用推送模式调用。 public void update(float temperature, float pressure, float humidity) {
this.temperature = temperature; ///别人调用update,将调用显示方法 display(); } //显示 public void display() {
System.out.println("***Today mTemperature: " temperature "***"); } }
核心天气类
- 推送逻辑
/** * 类是核心 * 1. 包括最新的天气信息 * 2. 含有 CurrentConditions 对象 * 3. 当数据更新时,主动调用 CurrentConditions对象update方法(含 display), * 这样,他们(访问者)就可以看到最新的信息 * */ public class WeatherData {
private float temperatrue; //加入第三方 private CurrentConditions currentConditions; public WeatherData(CurrentConditions currentConditions) {
this.currentConditions = currentConditions;
}
//当数据有更新时,就调用 setData
public void setData(float temperature, float pressure, float humidity) {
this.temperatrue = temperature;
//将最新的信息 推送给 接入方 currentConditions
//调用 接入方的 update
currentConditions.update(getTemperature(), getPressure(), getHumidity());
}
}
//创建接入方 currentConditions
CurrentConditions c = new CurrentConditions();
//创建 WeatherData 并将 接入方 currentConditions 传递到 WeatherData中
WeatherData w = new WeatherData(c);
//更新天气情况
w.setData(30, 150, 40);
//天气情况变化
System.out.println("============天气情况变化=============");
w.setData(40, 160, 20);
问题分析
- 其他第三方接入气象站获取数据的问题
- 无法在运行时动态的添加第三方 (新浪网站)
- 违反ocp原则=>观察者模式 //在WeatherData中, 当增加一个第三方,都需要创建一个对应的第三方的公告板 对象,并加入到dataChange, 不利于维护,也不是动态加入
public void dataChange() {
currentConditions.update(getTemperature(), getPressure(), getHumidity());
}
Observer
角色说明
观察者模式类似订牛奶业务
- 奶站/气象局: Subject
- 用户/第三方网站: Observer
主题接口 和 观察者介绍
Subject:登记注册、移除和通知
- registerObserver 注册
- removeObserver 移除
- notifyObservers() 通知所有的注册的用户,
-
根据不同需求,可以是更新数据,让用户来取,
-
也可能是实施推送,看具体需求定
Observer:接收输入
- 观察者模式:对象之间多对一依赖的一种设计方案,
- 被依赖的对象为Subject,依赖的对象为Observer,
- Subject通知Observer变化,
- 比如这里的奶站是Subject,是1的一方。
- 用户时Observer,是多的一方。
本次案例
Subject
- registerObserver
- remove
- notifyObservers
子类:
- WeatherData 有ArrayList 里面存 Observer
Observer
- update
子类:
- CurrentCondition 自己的天气公告
- Baidu
Client 依赖:Subject 和 Observer
主题接口
//接口, 让WeatherData 来实现
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
主题的实现
/** * 类是核心 * 1. 包含最新的天气情况信息 * 2. 含有 观察者集合,使用ArrayList管理 * 3. 当数据有更新时,就主动的调用 ArrayList, 通知所有的(接入方)就看到最新的信息 */
public class WeatherData implements Subject {
private float temperatrue;
//观察者集合
private ArrayList<Observer> observers;
//加入新的第三方
public WeatherData() {
observers = new ArrayList<Observer>();
}
//当数据有更新时,就调用 setData
public void setData(float temperature, float pressure, float humidity) {
this.temperatrue = temperature;
//将最新的信息 推送给 接入方 currentConditions
notifyObservers();
}
//遍历所有的观察者,并通知
@Override
public void notifyObservers() {
for(int i = 0; i < observers.size(); i++) {
observers.get(i).update(this.temperatrue, this.pressure, this.humidity);
}
}
//注册一个观察者
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
//移除一个观察者
@Override
public void removeObserver(Observer o) {
if(observers.contains(o)) {
observers.remove(o);
}
}
}
观察者接口
//观察者接口,有观察者来实现
public interface Observer {
public void update(float temperature, float pressure, float humidity);
}
观察者实现
- 现状类,就是 自己的项目
public class CurrentConditions implements Observer {
// 温度,气压,湿度
private float temperature;
// 更新 天气情况,是由 WeatherData 来调用,我使用推送模式
public void update(float temperature, float pressure, float humidity) {
this.temperature = temperature;
display();
}
// 显示
public void display() {
System.out.println("***Today mTemperature: " + temperature + "***");
}
}
Conditions
n.
条件,环境;疾病;条款(condition 的复数)
v.
训练,使习惯于;控制,制约;护理,保养;影响;加条件于(condition 的第三人称单数)
temperature
英
/ˈtemprətʃə(r)/
美
/ˈtemprətʃər; ˈtemprətʃʊr/
n.
温度,气温;体温;发烧;热烈程度,情绪激烈程度
pressure
英
/ˈpreʃə(r)/
美
/ˈpreʃər/
n.
压力,挤压;(气体或液体形成的)压力,压强;心理压力,紧张;催促,要求;气压
v.
对……施加压力,强迫;使……增压
humidity
英
/hjuːˈmɪdəti/
美
/hjuːˈmɪdəti/
n.
潮湿,湿气;湿度
测试
//创建一个 天气局
WeatherData w = new WeatherData();
//创建具体观察者,公告板 和 百度
CurrentConditions c = new CurrentConditions();
BaiduSite b = new BaiduSite();
//注册到 气象局
w.registerObserver(c);
w.registerObserver(b);
//测试
System.out.println("通知各个注册的观察者, 看看信息");
w.setData(10f, 100f, 30.3f);
//移除 公告板
w.removeObserver(c);
//测试
System.out.println("通知各个注册的观察者, 看看信息");
w.setData(10f, 100f, 30.3f);
通知各个注册的观察者, 看看信息
***Today mTemperature: 10.0***
***Today mPressure: 100.0***
***Today mHumidity: 30.3***
===百度网站====
***百度网站 气温 : 10.0***
***百度网站 气压: 100.0***
***百度网站 湿度: 30.3***
通知各个注册的观察者, 看看信息
===百度网站====
***百度网站 气温 : 10.0***
***百度网站 气压: 100.0***
***百度网站 湿度: 30.3***
模式好处
观察者模式的好处
- 观察者模式设计后,会以集合的方式来管理用户(Observer),包括注册,移除 和通知。
- 这样,我们增加观察者(这里可以理解成一个新的公告板),就不需要去修改核 心类WeatherData不会修改代码, 遵守了ocp原则。
Observable
-
jdk的
-
没有继承接口,类和接口 放在一起了。
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
public Observable() {
obs = new Vector<>();
}
public synchronized void addObserver(Observer o) {
if (!obs.contains(o)) {
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
}
}
public interface Observer {
void update(Observable o, Object arg);
}
观察者模式在Jdk应用的源码分析 3) 模式角色分析 - Observable 的作用和地位等价于 我们前面讲过Subject - Observable 是类,不是接口,类中已经实现了核心的方法 ,即管理Observer 的方法 add… delete … notify… - Observer 的作用和地位等价于我们前面讲过的 Observer, 有update - Observable 和 Observer 的使用方法和前面讲过的一样,只是Observable 是 类,通过继承来实现观察者模式
使用
主题 实现类
public class Weather extends Observable {
public Weather() {
// changed = true; 说明已经改变,为了 源码过校验,执行方法
setChanged();
}
}
具体观察者
public class BaiduSite implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println(arg.toString());
System.out.println(o.toString());
}
}
//创建 气象局
Weather o=new Weather();
//观察者
BaiduSite b =new BaiduSite();
//添加
o.addObserver(b);
//通知 观察者
o.notifyObservers("张三");
中介者
智能家庭项目:
- 智能家庭包括各种设备,闹钟、咖啡机、电视机、窗帘 等
- 主人要看电视时,各个设备可以协同工作,自动完成看电视的准备工作,比如流 程为: 闹铃响起->咖啡机开始做咖啡->窗帘自动落下->电视机开始播放
客户联系中介
- 中介给 房主 和 房主的妻子,房主的父亲 联系。
- 房主 和 房主的妻子,代码里 不让其联系 (否则会 很复杂)
传统的问题
- 当各电器对象有多种状态改变时,相互之间的调用关系会比较复杂
- 各个电器对象彼此联系, 你中有我,我中有你,不利于松耦合.
- 各个电器对象之间所传递的消息(参数),容易混乱
- 当系统增加一个新的电器对象时,或者执行流程改变时,代码的可维护性、扩展性 都不理想 考虑中介者模式
基本介绍
- 中介者模式(Mediator Pattern) , 用一个中介对象来封装一系列的对象交互。 中介者使各个对象不需要显式地相互引用,从而使其耦合松散,而且可以独立 地改变它们之间的交互
- 中介者模式属于行为型模式, 使代码易于维护
- 比如MVC模式, C(Controller控制器)是M(Model模型)和V(View视图)的中 介者,在前后端交互时起到了中间人的作用
Service 也是中介者,注入各种mapper,mapper之间是 不交互的。
colleague
英
/ˈkɒliːɡ/
美
/ˈkɑːliːɡ/
全球发音
简明 牛津 新牛津 韦氏 柯林斯 例句 百科
n.
同事,同僚
高中 | CET4 | CET6 | 考研 | IELTS | TOEFL | SAT
复数 colleagues
角色组成
-
Mediator
-
Concreate Mediator
- 有HashMap,聚合 Colleague,管理所有的同事类
- 完成 响应的操作 和 任务
-
Colleague
- Concreate Colleague 构造自己的时候,拿到 Mediator,调用相关的方法
- 都依赖中介者对象。他们之间没关系。
- Concreate Colleague2 本案例为 :TM CoffeMachine
- 有方法:send Message():
- 和 getMediator 返回:Mediator
- Concreate Colleague 构造自己的时候,拿到 Mediator,调用相关的方法
-
Client 依赖,Mediator 和 Colleague
alarm
英
/əˈlɑːm/
美
/əˈlɑːrm/
全球发音
简明 牛津 新牛津 韦氏 柯林斯 例句 百科
n.
警报;警报器;闹钟;惊恐,担忧
v.
使不安,使恐慌;给(门等)安装警报器
curtains
英
/ˈkɜːtənz/
美
/'kɜːtənz/
全球发音
简明 柯林斯 例句 百科
窗帘(curtain的复数)
be curtains for sb,对某人而言是灾难
设计模式
同事中介类
//同事抽象类
public abstract class Colleague {
private Mediator mediator;
public String name;
public Colleague(Mediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}
public Mediator GetMediator() {
return this.mediator;
}
public abstract void SendMessage(int stateChange);
}
闹钟 和 TV类
//具体的同事类
public class Alarm extends Colleague {
//构造器
public Alarm(Mediator mediator, String name) {
super(mediator, name);
//在创建Alarm 同事对象时,将自己放入到ConcreteMediator 对象中[集合]
mediator.Register(name, this);
}
public void SendAlarm(int stateChange) {
SendMessage(stateChange);
}
@Override
public void SendMessage(int stateChange) {
//调用的中介者对象的getMessage
this.GetMediator().GetMessage(stateChange, this.name);
}
}
public class TV extends Colleague {
public void StartTv() {
System.out.println("It's time to StartTv!");
}
public void StopTv() {
System.out.println("StopTv!");
}
}
咖啡机
public class CoffeeMachine extends Colleague {
public void StartCoffee() {
System.out.println("It's time to startcoffee!");
}
public void FinishCoffee() {
System.out.println("After 5 minutes!");
System.out.println("Coffee is ok!");
SendMessage(0);
}
}
中介者类
public abstract class Mediator {
//将给中介者对象,加入到集合中
public abstract void Register(String colleagueName, Colleague colleague);
//接收消息, 具体的同事对象发出
public abstract void GetMessage(int stateChange, String colleagueName);
public abstract void SendMessage();
}
具体中介者
//具体的中介者类 public class ConcreteMediator extends Mediator { //集合,放入所有的同事对象 private HashMap<String, Colleague> colleagueMap; private HashMap<String, String> interMap; public ConcreteMediator() { colleagueMap = new HashMap<String, Colleague>(); interMap = new HashMap<String, String>(); } @Override public void Register(String colleagueName, Colleague colleague) { colleagueMap.put(colleagueName, colleague); if (colleague instanceof Alarm) { interMap.put("Alarm", colleagueName); } else if (colleague instanceof CoffeeMachine) { interMap.put("CoffeeMachine", colleagueName); } else if (colleague instanceof TV) { interMap.put("TV", colleagueName); } else if (colleague instanceof Curtains) { interMap.put("Curtains", colleagueName); } } //具体中介者的核心方法 //1. 根据得到消息,完成对应任务 //2. 中介者在这个方法,协调各个具体的同事对象,完成任务 @Override public void GetMessage(int stateChange, String colleagueName) { //处理闹钟发出的消息 if (colleagueMap.get(colleagueName) instanceof Alarm) { if (stateChange == 0) { ((CoffeeMachine) (colleagueMap.get(interMap .get("CoffeeMachine")))).StartCoffee(); ((TV) (colleagueMap.get(interMap.get("TV")))).StartTv(); } else if (stateChange == 1) { ((TV) (colleagueMap.get(interMap.get("TV")))).StopTv(); } } else if (colleagueMap.get