观察者模式之Scala实现

Head First Design Pattern 书中第二章讲解了”观察者”模式的用法, 书中实例(气象台)是java写的. 这里用scala实现一下, 其中差异还是挺明显的.

scala一直强调:不可变为scala的美,可变为scala的丑. 但是在”观察者模式”的被观察者中,观察者的集合是可以被增删的,在这种时候,就要使用可变集合 (但是在并发处理的时候,尽量避免使用可变对象,因为使用当对象有状态了,你就需要锁,锁的性能损耗可比你使用一个val高很多很多).

有空应该把类图实现一下, 设计模式很容易用类图表示,也能帮着记忆


代码背景:

WeatherData类获取气象数据并更新给公告板, 而公告板有很多, 而且以后还会添加新的公告板. – 在此例中公告板是观察者,WeatherData是被观察者(也成为主题Subject)

代码如下:

//个人觉得,观察者模式的核心就是:观察者类调主题类的注册注销函数,而主题类则调用观察者类的更新函数,将数据发布给观察者 --这是两个对象间交互的`松耦合`

import scala.collection.mutable.ArrayBuffer

//抽象主题类
abstract class Subject {
    def registerObserver(o:Observer):Unit
    def removerObserver(o:Observer):Unit
    def notifyObservers:Unit;
}
//抽象观察者类
abstract class Observer{
    def update(t:Float,h:Float,p:Float):Unit
}

//具体的主题类,实现Subject类
class WeatherData(var t:Float=0,var h:Float=0,var p:Float=0) extends Subject {
    var observers = new ArrayBuffer[Observer]//可变list来记录注册的观察者
    //注册
    override def registerObserver(o:Observer):Unit = {
        observers += o
    }
    //注销
    override def removerObserver(o:Observer):Unit = {
        if(observers.indexOf(o)>=0) observers -= o
    }
    //通知
    override def notifyObservers():Unit = {
        observers.foreach(_.update(t,h,p))
    }
    // 设定数据:t温度,h湿度,p气压
    def set(t:Float,h:Float,p:Float):Unit = {
        this.t = t 
        this.h = h
        this.p = p
        notifyObservers
    }
}
//具体的观察者类(公告板)实现了Observer
class CurrentConditionsDisplay(weatherData:WeatherData,var t:Float = 0,var h:Float=0) extends Observer {
    weatherData.registerObserver(this) //将自己注册给被观察者,直接在类里写语句就相当于构造函数

    override def update(t:Float,h:Float,p:Float):Unit = {
        this.t = t 
        this.h = h
        display
    }

    def display:Unit={
        println("Current condition: "+t +"摄氏度,"+h+"%湿度")
    }
}
//另一个观察者类
class CoolIndexDisplay(weatherData:WeatherData,var t:Float = 0,var h:Float=0) extends Observer{
    weatherData.registerObserver(this)

    override def update(t:Float,h:Float,p:Float):Unit = {
        this.t = t 
        this.h = h
        display
    }

    def display:Unit={
        val m = t+h
        println("Cool Index: "+m)
    }
}

val weatherData = new WeatherData
val current = new CurrentConditionsDisplay(weatherData)
val index = new CoolIndexDisplay(weatherData)
weatherData.set(1,2,3)

运行结果:
运行结果


从网上找了另一个实现, 区别是他只有一个观察者类, 实例以名字来区分:

import scala.collection.mutable.ArrayBuffer

// 抽象观察类
abstract class Observer(var name: String) {
     // 支援盟友的方法
    def help(): Unit
    //被攻击的方法
    def beAttacked(allControlCenter: AllControlCenter): Unit
}

//具体观察者
class Player(name: String) extends Observer(name) {

    override def help(): Unit = println(s"坚持住,${name}来救你!")
    override def beAttacked(allControlCenter: AllControlCenter): Unit = {
        println(s"${name}被攻击")
        allControlCenter.notifyObserver(name)
    }
}

// 抽象目标类,战队控制中心
abstract class AllControlCenter(allyName: String) {
    // 观察者队列
     protected var players = new ArrayBuffer[Observer]()
    def join(observer: Observer):Unit = observer match {
        case o if players.exists(_.eq(o)) => println(s"${o.name}已加入${allyName}战队")
        case o: Observer => println(s"${o.name}加入${allyName}战队")
            players += observer
        case _ => println("异常")
    }

    def quit(observer: Observer):Unit = observer match {
        case o if players.exists(o.eq(_)) => println(s"${o.name}退出${allyName}战队")
            players -= observer
        case o if !players.exists(_.eq(o)) => println(s"${o.name}已退出${allyName}战队")
        case _ => println("异常")
    }
    def notifyObserver(oName: String): Unit
}

//具体目标类
class ConcreteAllyControlCenter(name: String) extends AllControlCenter(name) {
    override def notifyObserver(oName: String): Unit = oName match {
        case o if players.exists(_.name == o) => println(s"${name}战队紧急通知,盟友${oName}遭到攻击")
            players.filterNot(_.name == oName).foreach(_.help())
        case _ => println(s"$oName,您已不是战队${name}成员,无法通知战队您被攻击的消息")
    }

}


    val acc: AllControlCenter = new ConcreteAllyControlCenter("justSo")

    /**
     * 观察者对象
     */
    val play1: Observer = new Player("a")
    val play2: Observer = new Player("b")
    val play3: Observer = new Player("c")
    val play4: Observer = new Player("d")
    val play5: Observer = new Player("e")
    /**
     * 
     * 注册
     */
    acc.join(play1)
    acc.join(play2)
    acc.join(play3)
    acc.join(play3)
    acc.join(play4)
    acc.join(play5)
    acc.quit(play1)
    acc.quit(play1)

    play1.beAttacked(acc)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值