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

Hosted by uCoz