看一个项目需求
气象站项目,具体要求如下:
1)气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如发布到自己的网站)。
2)需要设计开放型API,便于其他第三方公司也能接入气象站获取数据。
3)提供温度、气压和湿度的接口
4)测量数据更新时,要能实时的通知给第三方
WeatherData类
通过对气象站项目的分析,我们可以初步设计出一个WeatherData类
说明:
1)通过getXxx方法,可以让第三方公司接入,并得到相关信息.
2)当数据有更新时,气象站通过调用dataChange() 去更新数据,当第三方再次获取时,就能得到最新数据,当然也可以推送。
普通方法:
CurrentConditions(当前的天气情况)
可以理解成是我们气象局的网站 //推送
这种普通方法我都设计不出来
WeatherData
class WeatherData {
private var mTemperature: Float = _
private var mPressure: Float = _
private var mHumidity: Float = _
private var mCurrentConditions: CurrentConditions = _
def this(mCurrentConditions: CurrentConditions) {
this
this.mCurrentConditions = mCurrentConditions
}
def getTemperature() = {
mTemperature
}
def getPressure() = {
mPressure
}
def getHumidity() = {
mHumidity
}
//将最新数据的 update 给mCurrentConditions
def dataChange() = {
mCurrentConditions.update(getTemperature(), getPressure(), getHumidity())
}
//设置最新的天气情况的方法
def setData(mTemperature: Float, mPressure: Float, mHumidity: Float) = {
this.mTemperature = mTemperature
this.mPressure = mPressure
this.mHumidity = mHumidity
dataChange()
}
}
CurrentConditions
在这里插入代码片
//气象局的天气公告板
class CurrentConditions {
private var mTemperature: Float = _
private var mPressure: Float = _
private var mHumidity: Float = _
def display(): Unit ={
println("***Today mTemperature: " + mTemperature + "***")
println("***Today mPressure: " + mPressure + "***")
println("***Today mHumidity: " + mHumidity + "***")
}
def update(mTemperature: Float, mPressure: Float, mHumidity: Float)={
this.mTemperature = mTemperature
this.mPressure = mPressure
this.mHumidity = mHumidity
display()
}
}
主程序InternetWeather:
object InternetWeather {
def main(args: Array[String]): Unit = {
val mCurrentConditions = new CurrentConditions
val mWeatherData = new WeatherData(mCurrentConditions)
//先更新自己的数据
mWeatherData.setData(30,150,40)
// mWeatherData.dataChange()
// mCurrentConditions.display()
}
}
问题分析
1)其他第三方公司接入气象站获取数据的问题
2)无法在运行时动态的添加第三方
//在WeatherData中,当增加一个第三方,都需要创建一个对应的第三方的公告板对象,并加入到dataChange, 不利于维护,也不是动态加入
观察者模式
观察者模式原理
观察者模式类似订牛奶业务
1)奶站/气象局:Subject
2)用户/第三方网站:Observer
Subject:登记注册、移除和通知
1)registerObserver 注册
2)removeObserver 移除
3)notifyObservers() 通知所有的注册的用户,根据不同需求,可以是更新数据,让用户来取,也可能是实施推送,看具体需求定
观察者模式原理
Observer:接收输入
注意Observer 中的update方法是给Subject 使用的
观察者模式:对象之间多对一依赖的一种设计方案,被依赖的对象为Subject,依赖的对象为Observer,Subject通知Observer变化,比如这里的奶站是Subject,是1的一方。用户时Observer,是多的一方。
回到刚开始的问题,使用观察者模式设计气象网站
设计类图:
观察者模式的好处
1)观察者模式设计后,会以集合的方式来管理用户(Observer),包括注册,移除和通知。
2)这样,我们增加观察者(这里可以理解成一个新的公告板),就不需要去修改核心类WeatherDataSt/不会修改代码。它可以作为一个独立的进程保持运行,无需重新加载。
Subject
ObServer
InternetWeather
object InternetWeather {
def main(args: Array[String]): Unit = {
//创建个月气象局的天气公告板
val mCurrentConditions = new CurrentConditions()
val mWeatherDataSt = new WeatherDataSt
//mCurrentConditions 注册
mWeatherDataSt.registerObserver(mCurrentConditions)
//创建一个新浪的天气公告板
val sinaCurrentConditions = new SinaCurrentConditions
mWeatherDataSt.registerObserver(sinaCurrentConditions)
//比如天气情况变化,这里设置最新数据
mWeatherDataSt.setData(20, 150, 40)
}
}
CurrentConditions
//气象局的公告板
class CurrentConditions extends ObServer {
private var mTemperature: Float = _
private var mPressure: Float = _
private var mHumidity: Float = _
def display() = {
println("***气象局的天气公告板 Today mTemperature: " + mTemperature + "***")
println("***气象局的天气公告板 Today mPressure: " + mPressure + "***")
println("***气象局的天气公告板 Today mHumidity: " + mHumidity + "***")
}
override def update(mTemperature: Float, mPressure: Float, mHumidity: Float) = {
//更新天气公告板
this.mTemperature = mTemperature
this.mPressure = mPressure
this.mHumidity = mHumidity
//显示
display()
}
}
WeatherDataSt
import scala.collection.mutable.ListBuffer
class WeatherDataSt extends Subject {
private var mTemperature: Float = _
private var mPressure: Float = _
private var mHumidity: Float = _
//集合,用于管理所有的观察者
private val mObservers: ListBuffer[ObServer] = ListBuffer()
def getTemperature() = {
mTemperature
}
def getPressure() = {
mPressure
}
def getHumidity() = {
mHumidity
}
def dataChange() = {
//一旦天气变化,就通知所有观察者
notifyObservers()
}
//天气变化
def setData(mTemperature: Float, mPressure: Float, mHumidity: Float) = {
this.mTemperature = mTemperature
this.mPressure = mPressure
this.mHumidity = mHumidity
dataChange()
}
//注册
override def registerObserver(o: ObServer): Unit = {
//加入到mObservers
mObservers.append(o)
}
//移除,比如某个第三方不想接入
override def removeObserver(o: ObServer): Unit = {
if (mObservers.contains(o)) {
mObservers -= o
}
}
//通知,天气情况变化了,我们就通知所有的观察者
override def notifyObservers(): Unit = {
for(observer <- mObservers) {
observer.update(mTemperature,mPressure,mHumidity)
}
}
}
SinaCurrentConditions
class SinaCurrentConditions extends ObServer {
private var mTemperature: Float = _
private var mPressure: Float = _
private var mHumidity: Float = _
def display() = {
if (this.mTemperature >40) {
println("***新浪的天气公告板 Today mTemperature: " + mTemperature + "*** 赶紧离开地球")
} else if (mTemperature > 16 && mTemperature < 28) {
println("***新浪的天气公告板 Today mTemperature: " + mTemperature + "*** 赶紧回到地球")
}
println("***新浪的天气公告板 Today mPressure: " + mPressure + "***")
println("***新浪的天气公告板 Today mHumidity: " + mHumidity + "***")
}
override def update(mTemperature: Float, mPressure: Float, mHumidity: Float) = {
//更新天气公告板
this.mTemperature = mTemperature
this.mPressure = mPressure
this.mHumidity = mHumidity
//显示
display()
}
}
我的总结图,比较low:
Java 内置观察者模式
java.util.Observable
1)Observable 的作用和地位等价于我们讲的Subject
2)Observable 是类,不是接口,已经实现了核心的方法 注册,移除和通知。
现在好像被弃用了,我也没有试过
— 韩顺平老师Scala视频笔记