abstract class SubjectObserver {
type S <: Subject
type O <: Observer
trait Subject requires S {
private var observers: List[O] = List()
def subscribe( obs: O ) =
observers = obs :: observers
def publish =
for( val obs <- observers ) obs.notify( this )
}
trait Observer {
def notify( sub: S ): unit;
}
}
abstract class AbstractSensorReader extends SubjectObserver {
type S <: Sensor
type O <: Display
trait Sensor requires S extends Subject {
var value: double = 0.0
def label: String
def changeValue( v: double ) = {
value = v
publish
}
}
trait Display extends Observer {
def label: String
override def notify( sub: S ) =
Console.println( "[" + label + "] " + sub.label +
" has value " + sub.value )
}
type C <: Calibrator
trait CalibrateableEntity {
private var c: Calibrator = null
def calibrator = c
def calibrator_=( v: Calibrator ) = c = v
}
trait CalibrateableSensor requires (S with CalibrateableEntity) extends Sensor {
override def changeValue( v: double ) = {
value = if( null != calibrator ) calibrator.adjustValue( this, v ) else v
publish
}
}
trait Calibrator {
def adjustValue( sensor: CalibrateableEntity, v: double ): double
}
}
object SensorReader extends AbstractSensorReader {
type S = Sensor
type O = Display
type C = Calibrator
class SimpleSensor( private val name: String ) extends Sensor {
override def label = name
}
class SimpleDisplay( private val name: String ) extends Display {
override def label = name
}
class Meter( private val name: String ) extends CalibrateableSensor with CalibrateableEntity {
override def label = name
}
class MeterCalibrator extends Calibrator {
import scala.collection.mutable.HashMap
type Map = HashMap[ CalibrateableEntity, double ]
private var calibration: Map = new Map
override def adjustValue(sensor: CalibrateableEntity, v: double ): double =
calibration.get( sensor ) match {
case Some(scale) => v * scale
case None => v
}
def addMeter( sensor: CalibrateableEntity, scale: double ) = {
calibration.update( sensor, scale )
sensor.calibrator = this
}
}
}
object AbstractTypesDemo extends Application {
import SensorReader._
val s1 = new SimpleSensor( "sensor1" )
val s2 = new SimpleSensor( "sensor2" )
val m1 = new Meter( "meter1" )
val d1 = new SimpleDisplay( "CRT" )
val d2 = new SimpleDisplay( "TFT" )
val d3 = new SimpleDisplay( "LCD" )
val c1 = new MeterCalibrator
c1.addMeter( m1, 1.2 )
s1.subscribe( d1 ); s1.subscribe( d2 )
s2.subscribe( d1 ); s2.subscribe( d2 )
m1.subscribe( d2 ); m1.subscribe( d3 )
s1 changeValue 2.1
s2 changeValue 3.2
m1 changeValue 3
}
// vim:ts=2:sts=2:sw=2:expandtab