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)