天气预报项目需求
天气预报项目需求,具体要求如下:
-
气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如
发布到自己的网站或第三方)。 -
需要设计开放型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 + "***");
}
}
核心天气类
- 推送逻辑
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();
}
主题的实现
public class WeatherData implements Subject {
private float temperatrue;
//观察者集合
private ArrayList observers;
//加入新的第三方
public WeatherData() {
observers = new ArrayList();
}
//当数据有更新时,就调用 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原则。
-
jdk的
-
没有继承接口,类和接口 放在一起了。
public class Observable {
private boolean changed = false;
private Vector 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 colleagueMap;
private HashMap interMap;
public ConcreteMediator() {
colleagueMap = new HashMap();
interMap = new HashMap();
}
@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(colleagueName) instanceof CoffeeMachine) {
((Curtains) (colleagueMap.get(interMap.get("Curtains"))))
.UpCurtains();
} else if (colleagueMap.get(colleagueName) instanceof TV) {
//如果TV发现消息
} else if (colleagueMap.get(colleagueName) instanceof Curtains) {
//如果是以窗帘发出的消息,这里处理...
}
}
@Override
public void SendMessage() {
}
}
使用
//创建一个中介者对象
Mediator mediator = new ConcreteMediator();
//创建Alarm 并且加入到 ConcreteMediator 对象的HashMap
Alarm alarm = new Alarm(mediator, "alarm");
//创建了CoffeeMachine 对象,并 且加入到 ConcreteMediator 对象的HashMap
CoffeeMachine coffeeMachine = new CoffeeMachine(mediator,
"coffeeMachine");
//创建 Curtains , 并 且加入到 ConcreteMediator 对象的HashMap
Curtains curtains = new Curtains(mediator, "curtains");
TV tV = new TV(mediator, "TV");
//让闹钟发出消息
alarm.SendAlarm(0);
System.out.println("==========================");
coffeeMachine.FinishCoffee();
System.out.println("==========================");
alarm.SendAlarm(1);
It's time to startcoffee! It's time to StartTv! ========================== After 5 minutes! Coffee is ok! I am holding Up Curtains! ========================== StopTv!注意细节
中介者模式的注意事项和细节
- 多个类相互耦合,会形成网状结构, 使用中介者模式将网状结构分离为星型结构,
进行解耦 - 减少类间依赖,降低了耦合, 符合迪米特原则
- 中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响
- 如果设计不当,中介者对象本身变得过于复杂, 这点在实际使用时,要特别注意



