Scala做了一些面向对象的创新,其中之一就是特质(Trait)。trait类似于带有部分实现的抽象类。
一个特质(trait)代表一个接口,由相关类的层级所支持。它是一个抽象机制,帮助开发模块化、可重用和可扩展的代码。
从概念上来说,接口是通过一系列方法所定义的。Scala trait 与Java 的接口类似。不过Java 中的接口只包括方法签名,而一个Scala 的trait 可以包含方法的实现。此外,一个Scala trait 也可以包含字段。一个类可以重用在trait 中实现的这些字段和方法。
一个trait 看上去与一个抽象类相似。都包含字段和方法。关键的区别在于一个类只能从一个类继承,但它可以从任意数量的trait 继承。
下面是一个trait 的例子:
trait Shape{
def area(): Int
}
class Square(length:Int) extends Shape{
def area = length * length;
}
class Rectangle(length:Int, width:Int) extends Shape{
def area = length * width;
}
val square = new Square(10);
val area = square.area;
在下面的代码中,定义了两个trait,并定义了实现这两个trait的类Batmobile:
// Trait(特质,类似于Java的接口)
trait flying{
def fly() = println("flying")
}
trait gliding{
def float() = println("gliding")
}
// 实现了Trait接口的类
class Batmobile(speed:Int) extends Vehicle(speed) with flying with gliding{
override val mph:Int = speed
override def race() = println("Racing Batmobile")
override def fly() = println("Flying Batmobile")
override def float() = println("Gliding Batmobile")
}
// 对象
val vehicle3 = new Batmobile(300)
vehicle3.fly
vehicle3.float
val vehicleList = List(vehicle1, vehicle2, vehicle3)
val fastestVehicle = vehicleList.maxBy(_.mph)
Scala特质说明:
-
Scala中同样像Java一样不能实现多继承,只能通过多实现来弥补,同时多实现,要比多继承灵活的多。
-
在Java中的实现,我们称之为接口interface,使用关键字implement;在Scala中,我们称之为特质trait,使用关键字extends。
-
如果在Java中实现的是多个接口,接口之间使用”,”隔开;如果在Scala中继承的是多个特质,特质之间使用with隔开
-
trait是一个比较特殊的结构,既可以有抽象方法,也可以有非抽象方法。如果trait中的方法都是抽象的,我们就可以将其看作Java的接口。
-
当我们扩展/继承的多个特质,拥有相同的方法的时候,默认只会调用最右面一个特质的方法。
下面的代码中,定义了一个特质log,它有一个抽象的方法log:
trait Log {
def log(msg:String): Unit = {
}
}
class ConsoleLog extends Log {
override def log(msg: String): Unit = {
println(s"将 ${msg} 输出到Console")
}
}
trait FileLog extends Log {
override def log(msg: String): Unit = {
println(s"将 ${msg} 输出到File")
super.log(msg)
}
}
trait FlumeLog extends Log {
override def log(msg: String): Unit = {
println(s"将 ${msg} 采集到Flume")
super.log(msg)
}
}
class MainLog extends FileLog with FlumeLog {
override def log(msg: String): Unit = {
super.log(msg)
}
}
// ======================================================================
val cLog:Log = new ConsoleLog
cLog.log("日志信息")
println("==================")
val mLog:MainLog = new MainLog
mLog.log("info")
下面是另一个简单的例子:
trait Animal
trait FurryAnimal extends Animal
case class Dog(name: String) extends Animal
case class Cat(name: String) extends Animal
val x = Array(Dog("Fido"), Cat("Felix"))
val x = Array[Animal](Dog("Fido"), Cat("Felix"))
【示例】简单trait示例。
// 定义一个trait,提供DAO层的方法签名
trait DonutShoppingCartDao{
def add(donutName: String): Long
def update(donutName: String): Boolean
def search(donutName: String): String
def delete(donutName: String): Boolean
}
// 创建一个DonutShoppingCart类,它扩展上面的trait并实现其方法
class DonutShoppingCart extends DonutShoppingCartDao {
override def add(donutName: String): Long = {
println(s"DonutShoppingCart -> add method -> donutName: $donutName")
1
}
override def update(donutName: String): Boolean = {
println(s"DonutShoppingCart -> update method -> donutName: $donutName")
true
}
override def search(donutName: String): String = {
println(s"DonutShoppingCart -> search method -> donutName: $donutName")
donutName
}
override def delete(donutName: String): Boolean = {
println(s"DonutShoppingCart -> delete method -> donutName: $donutName")
true
}
}
// 主类
object TraitDemo2 {
def main(args: Array[String]): Unit = {
// 现在我们可以创建DonutShoppingCart的实例
val donutShoppingCart1: DonutShoppingCart = new DonutShoppingCart()
// 并调用相应的add、update、search和delete方法
donutShoppingCart1.add("Vanilla Donut")
donutShoppingCart1.update("Vanilla Donut")
donutShoppingCart1.search("Vanilla Donut")
donutShoppingCart1.delete("Vanilla Donut")
println("----------------------------------------------")
// 因为我们的DonutShoppingCart类扩展了特性DonutShoppingCartDao,
// 也可以将DonutShoppingCart对象的类型分配给trait DonutShoppingCartDao
val donutShoppingCart2: DonutShoppingCartDao = new DonutShoppingCart()
donutShoppingCart2.add("Vanilla Donut")
donutShoppingCart2.update("Vanilla Donut")
donutShoppingCart2.search("Vanilla Donut")
donutShoppingCart2.delete("Vanilla Donut")
}
}
【示例】带类型参数的trait示例。
// 定义一个trait,提供DAO层的方法签名
trait DonutShoppingCartDao[A]{
def add(donut: A): Long
def update(donut: A): Boolean
def search(donut: A): A
def delete(donut: A): Boolean
}
// 创建一个DonutShoppingCart类,它扩展上面的trait并实现其方法
class DonutShoppingCart[A] extends DonutShoppingCartDao[A] {
override def add(donut: A): Long = {
println(s"DonutShoppingCart -> add method -> donut: $donut")
1
}
override def update(donut: A): Boolean = {
println(s"DonutShoppingCart -> update method -> donut: $donut")
true
}
override def search(donut: A): A = {
println(s"DonutShoppingCart -> search method -> donut: $donut")
donut
}
override def delete(donut: A): Boolean = {
println(s"DonutShoppingCart -> delete method -> donut: $donut")
true
}
}
// 主类
object TraitDemo3 {
def main(args: Array[String]): Unit = {
// 现在我们可以创建DonutShoppingCart的实例
val donutShoppingCart1: DonutShoppingCart[String] = new DonutShoppingCart[String]()
// 并调用相应的add、update、search和delete方法
donutShoppingCart1.add("Vanilla Donut")
donutShoppingCart1.update("Vanilla Donut")
donutShoppingCart1.search("Vanilla Donut")
donutShoppingCart1.delete("Vanilla Donut")
println("----------------------------------------------")
// 因为我们的DonutShoppingCart类扩展了特性DonutShoppingCartDao,
// 也可以将DonutShoppingCart对象的类型分配给trait DonutShoppingCartDao
val donutShoppingCart2: DonutShoppingCartDao[String] = new DonutShoppingCart[String]()
donutShoppingCart2.add("Vanilla Donut")
donutShoppingCart2.update("Vanilla Donut")
donutShoppingCart2.search("Vanilla Donut")
donutShoppingCart2.delete("Vanilla Donut")
}
}
【示例】扩展自多个trait的示例。
// 定义一个trait,提供DAO层的方法签名
trait DonutShoppingCartDao[A]{
def add(donut: A): Long
def update(donut: A): Boolean
def search(donut: A): A
def delete(donut: A): Boolean
}
// 创建第二个trait,它将定义检查商品库存的方法
trait DonutInventoryService[A] {
def checkStockQuantity(donut: A): Int
}
// 创建一个DonutShoppingCart类,它扩展上面的多个trait并实现其方法
class DonutShoppingCart[A] extends DonutShoppingCartDao[A] with DonutInventoryService[A] {
override def add(donut: A): Long = {
println(s"DonutShoppingCart -> add method -> donut: $donut")
1
}
override def update(donut: A): Boolean = {
println(s"DonutShoppingCart -> update method -> donut: $donut")
true
}
override def search(donut: A): A = {
println(s"DonutShoppingCart -> search method -> donut: $donut")
donut
}
override def delete(donut: A): Boolean = {
println(s"DonutShoppingCart -> delete method -> donut: $donut")
true
}
override def checkStockQuantity(donut: A): Int = {
println(s"DonutShoppingCart -> checkStockQuantity method -> donut: $donut")
10
}
}
// 主类
object TraitDemo3 {
def main(args: Array[String]): Unit = {
// 现在我们可以创建DonutShoppingCart的实例
val donutShoppingCart: DonutShoppingCart[String] = new DonutShoppingCart[String]()
// 并调用相应的add、update、search和delete方法
donutShoppingCart.add("Vanilla Donut")
donutShoppingCart.update("Vanilla Donut")
donutShoppingCart.search("Vanilla Donut")
donutShoppingCart.delete("Vanilla Donut")
donutShoppingCart.checkStockQuantity("Vanilla Donut")
}
}
【示例】使用标准Scala库来使用trait进行依赖注入,而无需导入任何第三方工具和库。
// 定义一个trait
trait DonutDatabase[A] {
def addOrUpdate(donut: A): Long
def query(donut: A): A
def delete(donut: A): Boolean
}
// 假设我们的存储层是Apache Cassandra。我们创建了一个名为CassandraDonutStore[A]的类,
// 它将通过扩展trait DonutDatabase[A]来促进所有的CRUD操作。
class CassandraDonutStore[A] extends DonutDatabase[A] {
override def addOrUpdate(donut: A): Long = {
println(s"CassandraDonutDatabase -> addOrUpdate method -> donut: $donut")
1
}
override def query(donut: A): A = {
println(s"CassandraDonutDatabase -> query method -> donut: $donut")
donut
}
override def delete(donut: A): Boolean = {
println(s"CassandraDonutDatabase -> delete method -> donut: $donut")
true
}
}
// 创建一个trait,它将定义数据访问层的方法,并将要求DonutDatabase的依赖注入
// 接下来,我们创建一个名为DonutShoppingCartDao的trait,它将是执行CRUD操作的主要API。
// 为此,我们定义了一个类型DonutDatabase[A]的val,它将被依赖注入。
trait DonutShoppingCartDao[A] {
val donutDatabase: DonutDatabase[A] // 依赖注入
def add(donut: A): Long = {
println(s"DonutShoppingCartDao -> add method -> donut: $donut")
donutDatabase.addOrUpdate(donut)
}
def update(donut: A): Boolean = {
println(s"DonutShoppingCartDao -> update method -> donut: $donut")
donutDatabase.addOrUpdate(donut)
true
}
def search(donut: A): A = {
println(s"DonutShoppingCartDao -> search method -> donut: $donut")
donutDatabase.query(donut)
}
def delete(donut: A): Boolean = {
println(s"DonutShoppingCartDao -> delete method -> donut: $donut")
donutDatabase.delete(donut)
}
}
// 创建一个trait,它将定义检查商品库存的方法,并且需要注入DonutDatabase依赖项
// 类似于前面的例子,我们创建了另一个trait,它将负责检查商品库存。
trait DonutInventoryService[A] {
val donutDatabase: DonutDatabase[A] // 依赖注入
def checkStockQuantity(donut: A): Int = {
println(s"DonutInventoryService-> checkStockQuantity method -> donut: $donut")
donutDatabase.query(donut)
1
}
}
// 创建一个trait,它将作为一个facade,并扩展多个trait,即DonutShoppingCartDao和DonutInventoryService。
// 我们还注入了存储层的一个实现,在本例中是CassandraDonutStore的一个实例
trait DonutShoppingCartServices[A] extends DonutShoppingCartDao[A] with DonutInventoryService[A] {
override val donutDatabase: DonutDatabase[A] = new CassandraDonutStore[A]()
}
// 创建一个DonutShoppingCart类,它扩展了一个名为DonutShoppingCartServices的外观,
// 以公开DonutShoppingCart所需的所有底层trait
class DonutShoppingCart[A] extends DonutShoppingCartServices[A] {
}
// 主类
object TraitDemo5 {
def main(args: Array[String]): Unit = {
// 创建DonutShoppingCart实例
val donutShoppingCart: DonutShoppingCart[String] = new DonutShoppingCart[String]()
// 并调用add、update、search和delete方法
donutShoppingCart.add("Vanilla Donut")
donutShoppingCart.update("Vanilla Donut")
donutShoppingCart.search("Vanilla Donut")
donutShoppingCart.delete("Vanilla Donut")
}
}
1 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
2 本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
3 本站资源大多存储在云盘,如发现链接失效,请联系我们我们会第一时间更新。
暂无评论内容