第 17 章 设计模式(4 >>> 观察者模式(Observer))

一、提出需求

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
每天进步一点点,也许某一天你也会变得那么渺小!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值