第7章——特质
Java 只允许单继承,这会强制建立一种线性的层次结构模型。但现实世界中充满了横切 关注点(crosscutting concerns)—一种横切且影响多个抽象的概念,这些抽象并不同属于 某个单一的类层次结构 ① 。在典型的企业级应用程序中,安全、日志记录、验证、事务以及 资源管理都是这些横切关注点的应用场景。但是,因为我们受限于单一的类层次结构,所以 实现这些横切关注点变得相当困难,往往需要代码上的重复或者引入重量级工具 ② 。Scala 使 用特质(trait)解决了这个问题。
- 即横跨应用程序中多个模块的特性。——译者注
7.1 理解特质
UsingTraits/HumanWithListen.scala
class Human(val name: String) {
def listen(): Unit = println(s"Your friend $name is listening")
}
class Man(override val name: String) extends Human(name)
class Woman(override val name: String) extends Human(name)
UsingTraits/Friend.scala
trait Friend {
val name: String
def listen(): Unit = println(s"Your friend $name is listening")
}
UsingTraits/Human.scala
class Human(val name: String) extends Friend
class Woman(override val name: String) extends Human(name)
class Man(override val name: String) extends Human(name)
UsingTraits/Dog.scala
class Dog(val name: String) extends Animal with Friend {
//optionally override method here.
override def listen(): Unit = println(s"$name's listening quietly")
}
UsingTraits/Animal.scala
class Animal
UsingTraits/UseFriend.scala
object UseFriend extends App {
val john = new Man("John")
val sara = new Woman("Sara")
val comet = new Dog("Comet")
john.listen()
sara.listen()
comet.listen()
val mansBestFriend: Friend = comet
mansBestFriend.listen()
def helpAsFriend(friend: Friend): Unit = friend.listen()
helpAsFriend(sara)
helpAsFriend(comet)
}
运行结果
Your friend John is listening
Your friend Sara is listening
Comet's listening quietly
Comet's listening quietly
Your friend Sara is listening
Comet's listening quietly
7.2 选择性混入
UsingTraits/Cat.scala
class Cat(val name: String) extends Animal
UsingTraits/UseCat.scala
object UseCat extends App {
def useFriend(friend: Friend): Unit = friend.listen()
val alf = new Cat("Alf")
val friend: Friend = alf // ERROR
useFriend(alf) // ERROR
}
编译结果
UseCat.scala:5: error: type mismatch;
found : Cat
required: Friend
val friend : Friend = alf // ERROR
^
UseCat.scala:7: error: type mismatch;
found : Cat
required: Friend
useFriend(alf) // ERROR
^
two errors found
UsingTraits/TreatCatAsFriend.scala
def useFriend(friend: Friend): Unit = friend.listen()
val angel = new Cat("Angel") with Friend
val friend: Friend = angel
angel.listen()
useFriend(angel)
运行结果
Your friend Angel is listening
Your friend Angel is listening
7.3 使用特质实现装饰器模式
UsingTraits/Decorator.scala
abstract class Check {
def check: String = "Checked Application Details..."
}
UsingTraits/Decorator.scala
trait CreditCheck extends Check {
override def check: String = s"Checked Credit... ${super.check}"
}
trait EmploymentCheck extends Check {
override def check: String = s"Checked Employment...${super.check}"
}
trait CriminalRecordCheck extends Check {
override def check: String = s"Check Criminal Records...${super.check}"
}
UsingTraits/Decorator.scala
val apartmentApplication =
new Check with CreditCheck with CriminalRecordCheck
println(apartmentApplication.check)
UsingTraits/Decorator.scala
val employmentApplication =
new Check with CriminalRecordCheck with EmploymentCheck
println(employmentApplication.check)
运行结果
Check Criminal Records...Checked Credit... Checked Application Details...
Checked Employment...Check Criminal Records...Checked Application
Details...
7.4 特质中的方法延迟绑定
UsingTraits/MethodBinding.scala
abstract class Writer {
def writeMessage(message: String): Unit
}
UsingTraits/MethodBinding.scala
trait UpperCaseWriter extends Writer {
abstract override def writeMessage(message: String): Unit =
super.writeMessage(message.toUpperCase)
}
trait ProfanityFilteredWriter extends Writer {
abstract override def writeMessage(message: String): Unit =
super.writeMessage(message.replace("stupid", "s-----"))
}
UsingTraits/MethodBinding.scala
class StringWriterDelegate extends Writer {
val writer = new java.io.StringWriter
def writeMessage(message: String): Unit = writer.write(message)
override def toString: String = writer.toString
}
UsingTraits/MethodBinding.scala
val myWriterProfanityFirst =
new StringWriterDelegate with UpperCaseWriter with ProfanityFilteredWriter
val myWriterProfanityLast =
new StringWriterDelegate with ProfanityFilteredWriter with UpperCaseWriter
myWriterProfanityFirst.writeMessage("There is no sin except stupidity")
myWriterProfanityLast.writeMessage("There is no sin except stupidity")
println(myWriterProfanityFirst)
println(myWriterProfanityLast)
运行结果
THERE IS NO SIN EXCEPT S-----ITY
THERE IS NO SIN EXCEPT STUPIDITY
1.0.0