Composing simple traits
Let's see an example where we compose simple traits, which do not extend other traits or classes:
class Watch(brand: String, initialTime: Long) {
def getTime(): Long = System.currentTimeMillis() - initialTime
}
object WatchUser {
def main(args: Array[String]): Unit = {
val expensiveWatch = new Watch("expensive brand", 1000L) with Alarm with Notifier {
override def trigger(): String = "The alarm was triggered."
override def clear(): Unit = {
System.out.println("Alarm cleared.")
}
override val notificationMessage: String = "Alarm is running!"
}
val cheapWatch = new Watch("cheap brand", 1000L) with Alarm {
override def trigger(): String = "The alarm was triggered."
}
// show some watch usage.
System.out.println(expensiveWatch.trigger())
expensiveWatch.printNotification()
System.out.println(s"The time is ${expensiveWatch.getTime()}.")
expensiveWatch.clear()
System.out.println(cheapWatch.trigger())
System.out.println("Cheap watches cannot manually stop the alarm...")
}
}
In the preceding example, we used the Alarm and Notifier traits from before. We created two watch instances—one is expensive that has more functionality and is more useful, and the other one is a cheap one that does not give too much control. Essentially, they are anonymous classes, which are defined during instantiation. Another thing to note is that, as expected, we have to implement the abstract methods from the traits we include. I hope this gives you an idea of how many combinations there might be in the cases where we have more traits.
Just for the sake of completeness, here is an example output of the preceding program:
The alarm was triggered.
Alarm is running!
The time is 1234567890562.
Alarm cleared.
The alarm was triggered.
Cheap watches cannot manually stop the alarm...
As expected, the highlighted time value will be different in the different runs.