一、提出需求
1、气象站项目,具体要求如下:
1. 气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如发布到自己的网站);
2. 需要设计开放型API,便于其他第三方公司也能接入气象站获取数据;
3. 提供温度、气压和湿度的接口;
4. 测量数据更新时,要能实时的通知给第三方。
2、WeatherData类
通过对气象站项目的分析,我们可以初步设计出一个WeatherData类。
设计图:
设计图说明:
1. 通过getXxx方法,可以让第三方公司接入,并得到相关信息;
2. 当数据有更新时,气象站通过调用dataChange() 去更新数据,当第三方再次获取时,就能得到最新数据,
当然也可以推送。
二、气象局方案设计
1、 方案一:普通方案
说明:CurrentConditions(当前的天气情况),可以理解成是气象局的网站 //推送。
2、方案一代码实现
===============================class CurrentConditions===============================
package com.lj.akka.observermode
/**
* @author Administrator
* @create 2020-03-28
*/
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): Unit = {
this.mTemperature = mTemperature
this.mPressure = mPressure
this.mHumidity = mHumidity
// 显示更新的信息
disPlay()
}
}
===============================class WeatherData===============================
package com.lj.akka.observermode
/**
* @author Administrator
* @create 2020-03-28
*/
class WeatherData {
// 温度
private[this] var _mTemperature: Float = _
// 压力
private[this] var _mPressure: Float = _
// 湿度
private[this] var _mHumidity: Float = _
private[this] var _mCurrentConditions: CurrentConditions = _
def this(mCurrentConditions: CurrentConditions) {
this
this._mCurrentConditions = mCurrentConditions
}
def mTemperature: Float = _mTemperature
def mTemperature_=(value: Float): Unit = {
_mTemperature = value
}
def mPressure: Float = _mPressure
def mPressure_=(value: Float): Unit = {
_mPressure = value
}
def mHumidity: Float = _mHumidity
def mHumidity_=(value: Float): Unit = {
_mHumidity = value
}
def dataChange(mCurrentConditions: CurrentConditions) = {
mCurrentConditions.update(_mTemperature, _mPressure, _mHumidity)
}
def mCurrentConditions_=(mTemperature: Float, mPressure: Float, mHumidity: Float): Unit= {
this._mTemperature = mTemperature
this._mPressure = mPressure
this._mHumidity = mHumidity
dataChange(_mCurrentConditions)
}
}
===============================使用:object InternetWeather===============================
package com.lj.akka.observermode
/**
* @author Administrator
* @create 2020-03-28
*/
object InternetWeather {
def main(args: Array[String]): Unit = {
val mCurrentConditions = new CurrentConditions
val mWeatherData = new WeatherData(mCurrentConditions)
mWeatherData.mCurrentConditions_=(23, 180, 35)
}
}
3、方案一问题分析
1. 其他第三方公司接入气象站获取数据的问题;
2. 无法在运行时动态的添加第三方。
3. 在WeatherData中,当增加一个第三方,都需要创建一个对应的第三方的公告板对象,并加入到dataChange,
不利于维护,也不是动态加入
def dataChange() = {
mCurrentConditions.update(getTemperature(), getPressure(), getHumidity())
}
三、观察者模式原理
1、设计图
2、设计图分析
** > 观察者模式类似订牛奶业务**
1. 奶站/气象局:Subject
2. 用户/第三方网站:Observer
> Subject:登记注册、移除和通知
1. registerObserver 注册;
2. removeObserver 移除;
3. notifyObservers() 通知所有的注册的用户,根据不同需求,可以是更新数据,让用户来取,也可能是实施推送,
看具体需求定。
> Observer:接收输入
观察者模式:对象之间多对一依赖的一种设计方案,被依赖的对象为Subject,依赖的对象为Observer,Subject通知Observer变化,比如这里的奶站是Subject,是1的一方。用户是Observer,是多的一方。
四、气象站设计方案二(观察者模式)
1、设计类图
2、观察者模式的好处
1. 观察者模式设计后,会以集合的方式来管理用户(Observer),包括注册,移除和通知。
2. 这样,我们增加观察者(这里可以理解成一个新的公告板),就不需要去修改核心类WeatherDataSt,即不会修
改代码。它可以作为一个独立的进程保持运行,无需重新加载。
五、观察者模式实现功能需求
1、代码结构图
2、代码实现
==============================trait Subject==============================
package com.lj.akka.observermode.myobserver
/**
* @author Administrator
* @create 2020-03-28
*/
trait Subject {
// 注册
def registerObserver(observer: Observer)
// 移除
def removeObserver(observer: Observer)
// 通知
def notifyObserver()
}
==============================trait Observer==============================
package com.lj.akka.observermode.myobserver
/**
* @author Administrator
* @create 2020-03-28
*/
trait Observer {
// 更新
def update(mTemperature: Float, mPressure: Float, mHumidity: Float)
def getName(): String
}
==========================class CurrentConditions extends Observer==========================
package com.lj.akka.observermode.internetweather.mode
import com.lj.akka.observermode.myobserver.Observer
/**
* @author Administrator
* @create 2020-03-28
*/
// 第三方板块
class CurrentConditions extends Observer {
private var mTemperature: Float = _
private var mPressure: Float = _
private var mHumidity: Float = _
var name: String = "Current"
def display(): Unit = {
println(s"---------------${name}播报天气预报:--------------------")
println("Update Current Today Temperature:" + mTemperature)
println("Update Current Today Pressure:" + mPressure)
println("Update Current Today Humidity:" + mHumidity)
}
override def update(mTemperature: Float, mPressure: Float, mHumidity: Float): Unit = {
this.mTemperature = mTemperature
this.mPressure = mPressure
this.mHumidity = mHumidity
display()
}
override def getName(): String = {
this.name
}
}
==============================trait Subject==============================
package com.lj.akka.observermode.internetweather.mode
import com.lj.akka.observermode.myobserver.Observer
/**
* @author Administrator
* @create 2020-03-28
*/
// 第三方板块
class TMConditions extends Observer {
private var mTemperature: Float = _
private var mPressure: Float = _
private var mHumidity: Float = _
val name: String = "TM"
def display(): Unit = {
println(s"---------------${name}播报天气预报:--------------------")
println("Update TM Today Temperature:" + mTemperature)
println("Update TM Today Pressure:" + mPressure)
println("Update TM Today Humidity:" + mHumidity)
}
override def update(mTemperature: Float, mPressure: Float, mHumidity: Float): Unit = {
this.mTemperature = mTemperature
this.mPressure = mPressure
this.mHumidity = mHumidity
display()
}
override def getName(): String = {
this.name
}
}
==============================class WeatherData extends Subject==============================
package com.lj.akka.observermode.internetweather.mode
import com.lj.akka.observermode.myobserver.{Observer, Subject}
import scala.collection.mutable.ListBuffer
/**
* @author Administrator
* @create 2020-03-28
*/
class WeatherData extends Subject{
private var _mTemperature: Float = _
private var _mPressure: Float = _
private var _mHumidity: Float = _
private val mObservers: ListBuffer[Observer] = ListBuffer()
def mTemperature: Float = _mTemperature
def mTemperature_=(value: Float) = {
_mTemperature = value
}
def mPressure: Float = _mPressure
def mPressure_=(value: Float): Unit = {
_mPressure = value
}
def mHumidity: Float = _mHumidity
def mHumidity_=(value: Float) = {
_mHumidity = value
}
def dataChange(): Unit = {
println("气象局检测到天气变化,通知第三方......")
notifyObserver()
}
def setData(mTemperature: Float, mPressure: Float, mHumidity: Float): Unit = {
mTemperature_=(mTemperature)
mPressure_=(mPressure)
mHumidity_=(mHumidity)
dataChange()
}
override def registerObserver(observer: Observer): Unit = {
if (!mObservers.contains(observer)) {
mObservers.append(observer)
println(s"气象局收到第三方 ${observer.getName()} 的订购指令,并订购成功。")
}
}
override def removeObserver(observer: Observer): Unit = {
println("气象局收到")
if (mObservers.contains(observer)) {
mObservers -= observer
println(s"气象局收到第三方 ${observer.getName()} 的退订指令,并退订成功。")
}
}
override def notifyObserver(): Unit = {
for (observer <- mObservers) {
println("通知:" + observer.getName() + " 天气发生了变化......")
observer.update(mTemperature, mPressure, mHumidity)
}
}
}
==============================object InternetWheather==============================
package com.lj.akka.observermode
import com.lj.akka.observermode.internetweather.mode.{CurrentConditions, TMConditions, WeatherData}
/**
* @author Administrator
* @create 2020-03-28
*/
object InternetWheather {
def main(args: Array[String]): Unit = {
val mWeatherData = new WeatherData
val mCurrentConditions = new CurrentConditions
val mTMConditions = new TMConditions
// 注册
mWeatherData.registerObserver(mCurrentConditions)
mWeatherData.registerObserver(mTMConditions)
// 更新天气
mWeatherData.setData(15, 30, 43)
// 移除
mWeatherData.removeObserver(mTMConditions)
}
}
=================================运行结果=======================================
气象局收到第三方 Current 的订购指令,并订购成功。
气象局收到第三方 TM 的订购指令,并订购成功。
气象局检测到天气变化,通知第三方......
通知:Current 天气发生了变化......
---------------Current播报天气预报:--------------------
Update Current Today Temperature:15.0
Update Current Today Pressure:30.0
Update Current Today Humidity:43.0
通知:TM 天气发生了变化......
---------------TM播报天气预报:--------------------
Update TM Today Temperature:15.0
Update TM Today Pressure:30.0
Update TM Today Humidity:43.0
气象局收到
气象局收到第三方 TM 的退订指令,并退订成功。
=================================运行结果=======================================
3、Java内置观察者模式
1. java.util.Observable
1. Observable 的作用和地位等价于,我们讲的Subject;
2. Observable 是类,不是接口,已经实现了核心的方法 注册,移除和通知,如下图。
2. java.util.Observer
1. Observer 的作用和地位等价于我们讲的Observer;
2. java.util.Observer的源码如下:
package java.util;
public interface Observer {
void update(Observable var1, Object var2);
}
3. Observable和Observer的使用方法和前面讲的案例基本一样,只是Observable是类,通过继承来实现观察者模式。
对以前的知识回顾,加深基础知识!
学习来自:北京尚硅谷韩顺平老师—尚硅谷大数据技术之Scala
每天进步一点点,也许某一天你也会变得那么渺小!!!