Scala Design Patterns.
上QQ阅读APP看书,第一时间看更新

Composing complex traits

It is possible that in some cases, we would have to compose more complex traits, which extend other traits or classes. If a trait and no other trait up the inheritance chain extends a specific class explicitly, then things will be pretty simple and they don't change much. In this case, we would simply have access to the methods from the super traits. However, let's see what happens if any of the traits in the hierarchy extend a specific class. For the next example, we will be using the ConnectorWithHelper trait defined previously. This trait extends the abstract Connector class. Imagine that we want to have another really expensive smart watch, which can also connect to a database:

object ReallyExpensiveWatchUser {
def main(args: Array[String]): Unit = {
val reallyExpensiveWatch = new Watch("really expensive brand", 1000L) with ConnectorWithHelper {
override def connect(): Unit = {
System.out.println("Connected with another connector.")
}
override def close(): Unit = {
System.out.println("Closed with another connector.")
}
}

System.out.println("Using the really expensive watch.")
reallyExpensiveWatch.findDriver()
reallyExpensiveWatch.connect()
reallyExpensiveWatch.close()
}
}

It seems that everything is fine; however, when we compile, we get the following error message:

Error:(36, 80) illegal inheritance; superclass Watch
is not a subclass of the superclass Connector
of the mixin trait ConnectorWithHelper
val reallyExpensiveWatch = new Watch("really expensive brand", 1000L) with ConnectorWithHelper {
^

This error message tells us that since the ConnectorWithHelper trait extends the Connector class, all the classes that use this trait for composition must be subclasses of Connector. Let's now imagine that we wanted to mix in another trait that also extends a class, but a different one in this case. According to the preceding logic, it will be required that Watch should also be a subclass of the other class. This, however, wouldn't be possible, as we can only extend one class at a time and this is how Scala limits multiple inheritance in order to prevent dangerous errors from happening.

If we want to fix the compilation issue in the example, we will have to modify the original Watch class and make sure it is a subclass of Connector. This, however, might not be desired and some refactoring might be needed in such cases.