★ Scala ★——Trait特质大全细则

Trait 特质

      • 1.1 概述
      • 1.2 特点
      • 1.3 对象混入trait
    • 使用trait实现适配器模式
      • 1.1设计模式简介
    • 使用trait实现模板方法模式
      • 1.1 概述
    • 使用trait实现职责链模式
    • trait的构造机制
      • 构造机制规则
    • trait继承class

★ Scala ★——方法def 与 函数 细则,99乘法表案例实现

★ Scala ★——类和对象(伴生对象)大全细则

★ Scala ★——继承、方法重写、抽象类、匿名类大全细则

★ Scala ★——Trait特质大全细则

★ Scala ★ —— 数据结构(列表、元组、数组)

★ Scala ★ —— 数据结构(集、映射、迭代器)

  • 目标
  1. 能够使用trait独立完成适配器, 模板方法, 职责链设计模式
  2. 能够独立叙述trait的构造机制
  3. 能够了解trait继承class的写法

1.1 概述

有些时候, 我们会遇到一些特定的需求, 即: 在不影响当前继承体系的情况下, 对某些类(或者某些对象)的功能进行加强, 例如: 有猴子类和大象类, 它们都有姓名, 年龄, 以及吃的功能, 但是部分的猴子经过马戏团的训练后, 学会了骑独轮车. 那骑独轮车这个功能就不能定义到父类(动物类)或者猴子类中, 而是应该定义到特质中,而Scala中的特质, 要用关键字 trait 修饰。

1.2 特点

  • 特质可以提高代码的复用性
  • 特质可以提高代码的扩展性和可维护性
  • 类与特质之间是继承关系, 只不过类与类之间只支持单继承
  • 类与特质之间, 既可以单继承, 也可以多继承
  • Scala的特质中可以有普通字段, 抽象字段, 普通方法, 抽象方法

注意:

  1. 如果特质中只有抽象内容, 这样的特质叫: 瘦接口
  2. 如果特质中既有抽象内容, 又有具体内容, 这样的特质叫: 富接口
定义特质:
trait 特质名称 {
	 // 普通字段 
	 // 抽象字段 
	 
	 // 普通方法 
	 // 抽象方法 
}

继承特质:
classextends 特质1 with 特质2 {
 	// 重写抽象字段
  	// 重写抽象方法 
}

注意

  • scala中不管是类还是特质, 继承关系用的都是 extends 关键字。
  • 如果要继承多个特质(trait),则特质名之间使用 with 关键字隔开。
  • 类继承单个、多个特质,单例对象(object)继承特质
  • 定义一个特质Logger, 添加log(msg:String)方法.
  • 定义一个特质Writer, 添加word(:String)方法.
  • 定义单例对象SoleLogger, 继承上述两个特质, 并重写两个方法
  • 定义ConsoleLogger类, 继承上述两个特质, 并重写log方法
package Trait0

object ClassDemo1 {
  def main(args: Array[String]): Unit = {
    val c = new ConsoleLogger
    c.log("yield v.收获,屈服")
    c.word("entrepreneur n. 创办者;企业家")

    println("--"*20)

    val s = SoleLogger
    s.log("\nfarm n.农场,v.收割")
    s.word("\nhoneydew n.蜜露")
  }

  // 定义一个特质Logger, 添加log(msg:String)方法.
  trait Logger{
    def log(msg:String)
  }

  // 定义一个特质Writer, 添加word(:String)方法.
  trait Writer{
    def word(w:String) = println(s"单词是:${w}")
  }

  // 定义单例对象SoleLogger, 继承上述两个特质, 并重写两个方法
  object SoleLogger extends Writer with Logger{
    override def log(msg: String): Unit = println(s"单列对象单词: drastic a.剧烈的 ${msg}")

    override def word(w: String): Unit = println((s"单列对象单词: rethought v. 再次考虑;再次思考 ${w}")
    )
  }
  
  // 定义ConsoleLogger类, 继承上述两个特质, 并重写log方法
  class ConsoleLogger extends Logger with Writer {
    override def log(msg: String): Unit = println(s"trait 特质的继承 ${msg}")
  }
}

★ Scala ★——Trait特质大全细则_第1张图片

1.3 对象混入trait

有些时候, 我们希望在不改变类继承体系的情况下, 对对象的功能进行临时增强或者扩展, 这个时候就可以考虑使用 对象混入 技术了. 所谓的 对象混入 指的就是: 在scala中, 类和特质之间无任何的继承关系, 但是通过特定的关键字, 却可以让该类对象具有指定特质中的成员。

val/var 对象名 = new 类 with 特质

  • 需求
  1. 创建Logger特质, 添加log(msg:String)方法
  2. 创建一个User类, 该类和Logger特质之间无任何关系
  3. 在main方法中测试, 通过对象混入技术让User类的对象具有Logger特质的log()方法
package Trait0

object ClassDemo2 {

  // 定义一个特质Logger, 添加log(msg:String)方法.
  trait Logger{
    def log(msg:String) = println(msg)
  }
  // 创建一个User类, 该类和Logger特质之间无任务关系.
  class User

  def main(args: Array[String]): Unit = {
    val u = new User with Logger      // 对象混入
    u.log("yield v.收获;屈服\nhoneydew n.蜜露\nproduce v.生产 \nfeed v.喂养;投喂")
  }
}

★ Scala ★——Trait特质大全细则_第2张图片

使用trait实现适配器模式

1.1设计模式简介

设计模式(Design Pattern) 是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它并不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。
设计模式一共有23种, 分为如下的3类:

  1. 创建型
    指的是: 需要创建对象的. 常用的模式有: 单例模式, 工厂方法模式。

  2. 结构型
    指的是: 类,特质之间的关系架构. 常用的模式有: 适配器模式, 装饰模式。

  3. 行为型
    指的是: 类(或者特质)能够做什么. 常用的模式有:模板方法模式, 职责链模式。

trait 特质A{ 
	// 抽象方法1 
	// 抽象方法2 
	// 抽象方法3 
	//... 
}
abstract class 类B extends A{ //适配器类 
	// 重写抽象方法1, 方法体为空 
	// 重写抽象方法2, 方法体为空 
	// 重写抽象方法3, 方法体为空 
	//... 
}
class 自定义类C extends 类B {
	 // 需要使用哪个方法, 重写哪个方法即可. 
}
  • 需求
  1. 定义特质PlayLOL, 添加6个抽象方法, 分别为: top(), mid(), adc(), support(), jungle(), schoolchild()
    解释: top: 上单, mid: 中单, jungle: 打野
  2. 定义抽象类Player, 继承PlayLOL特质, 重写特质中所有的抽象方法, 方法体都为空.
  3. 定义普通类GreenHand, 继承Player, 重写top()方法.
  4. 定义main方法, 在其中创建GreenHand类的对象, 并调用其方法进行测试。
package Trait0
object ClassDemo3 {
  // 定义3个抽象方法
  trait PlayLOL {
    def top() //上单
    def mid() //中单
    def jungle() //打野
  }

  // 抽象类Player, 继承PlayLOL特质, 重写特质中所有的抽象方法, 方法体都为空.
  // Player类充当的角色就是: 适配器类.
  class Player extends PlayLOL {
    override def top(): Unit = {}
    override def mid(): Unit = {}
    override def jungle(): Unit = {}
  }

  //  定义普通类GreenHand, 继承Player, 重写top()方法
  class GreenHand extends Player {
    override def top():Unit = println("上单:technology n.技术\ntechnological a.技术上的")
  }

  def main(args: Array[String]): Unit = {
    val g = new GreenHand
    g.top()
  }
}

★ Scala ★——Trait特质大全细则_第3张图片

使用trait实现模板方法模式

在现实生活中, 我们会遇到论文模板, 简历模板, 包括PPT中的一些模板等, 而在面向对象程序设计过程中,程序员常常会遇到这种情况:设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关。

1.1 概述

在Scala中, 我们可以先定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤, 这就是: 模板方法设计模式

优点

  1. 扩展性更强. 父类中封装了公共的部分, 而可变的部分交给子类来实现
  2. 符合开闭原则。
    部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能

缺点

  1. 类的个数增加, 导致系统更加庞大, 设计也更加抽象。
    因为要对每个不同的实现都需要定义一个子类

  2. 提高了代码阅读的难度。
    父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构

class A { 
	//父类, 封装的是公共部分 
	def 方法名(参数列表) = { //具体方法, 在这里也叫: 模板方法 
		//步骤1, 已知. 
		//步骤2, 未知, 调用抽象方法 
		//步骤3, 已知. //步骤n... 
	}
	
	// 抽象方法 
}
class B extends A { 
	//重写抽象方法 
}

注意: 抽象方法的个数要根据具体的需求来定, 并不一定只有一个, 也可以是多个

  • 需求
  1. 定义一个模板类Template, 添加code()和getRuntime()方法, 用来获取某些代码的执行时间
  2. 定义类ForDemo继承Template, 然后重写code()方法, 用来计算打印10000次"Hello,Scala!"的执行时间
  3. 定义main方法, 用来测试代码的具体执行时间
package Trait0

object ClassDemo4 {
//  定义一个模板类Template, 添加code()和getRuntime()方法
  abstract class Template{
    def code()

    def getRuntime() = {
      val start = System.currentTimeMillis()

      code()

      val end = System.currentTimeMillis()
      end - start
    }
  }
  
 // 定义类ForDemo继承Template, 然后重写getRuntime()方法
  class ForDemo extends Template{
    override def code(): Unit = for(i <- 1 to 10000) println("entrepreneurs n.企业家;创办者")
  }

  def main(args: Array[String]): Unit = {
    println(new ForDemo().getRuntime()) // 测试执行时间
  }
}

★ Scala ★——Trait特质大全细则_第4张图片

使用trait实现职责链模式

1 概述
多个trait中出现了同一个方法, 且该方法最后都调用了super.该方法名(), 当类继承了这多个trait后, 就可以依次调用多个trait中的此同一个方法了, 这就形成了一个调用链。

  • 执行顺序为:
  1. 按照 从右往左 的顺序依次执行. 即首先会先从最右边的trait方法开始执行,然后依次往左执行对应trait中的方法
  2. 当所有子特质的该方法执行完毕后, 最后会执行父特质中的此方法
    这种设计思想就叫: 职责链设计模式
  • 步骤
  1. 定义一个Handler特质, 添加具体的handle(data:String)方法,表示处理数据(具体的支付逻辑)
  2. 定义一个DataValidHandler特质,继承Handler特质.
    重写handle()方法,打印"验证数据", 然后调用父特质的handle()方法
  3. 定义一个SignatureValidHandler特质,继承Handler特质.
    重写handle()方法, 打印"检查签名", 然后调用父特质的handle()方法
  4. 创建一个Payment类, 继承DataValidHandler特质和SignatureValidHandler特质
    定义pay(data:String)方法, 打印"用户发起支付请求", 然后调用父特质的handle()方法
  5. 添加main方法, 创建Payment对象实例, 然后调用pay()方法
package Trait0

// 案例: 演示职责链模式(也叫: 调用链模式)
object ClassDemo05 {
  // 定义一个父特质 Handler, 表示处理数据(具体的支付逻辑)
  trait Handler {
    def handle(data:String) = {
      println("具体处理数据的代码(例如: 转账逻辑)")
      println(data)
    }
  }

  // 定义一个子特质 DataValidHandler, 表示 校验数据.
  trait DataValidHandler extends Handler {
    override def handle(data:String) = {
      println("校验数据...")
      super.handle(data)   // 调用父类!
    }
  }
  // 定义一个子特质 SignatureValidHandler, 表示 校验签名.
  trait SignatureValidHandler extends Handler {
    override def handle(data:String) = {
      println("校验签名...")
      super.handle(data)    // 调用父类!
    }
  }
  // 定义一个类Payment, 表示: 用户发起的支付请求.
  class Payment extends DataValidHandler with SignatureValidHandler {
    def pay(data:String) = {
      println("用户发起支付请求...")
      super.handle(data)    // 调用父类!
    }
  }

  def main(args: Array[String]): Unit = {
    // 创建Payment类的对象, 模拟: 调用链.
    val pm = new Payment
    pm.pay("digital a.数字化的\n 转账10000元\nincome n.收入")
  }
}

★ Scala ★——Trait特质大全细则_第5张图片

trait的构造机制

构造机制规则

  • 每个特质只有 一个无参数 的构造器。也就是说: trait也有构造代码,但和类不一样,特质不能有构造器参数

  • 遇到一个类继承另一个类、以及多个trait的情况,当创建该类的实例时,它的构造器执行顺序如下:

  1. 执行父类的构造器
  2. 按照 从左到右 的顺序, 依次执行trait的构造器
  3. 如果trait有父trait,则先执行父trait的构造器
  4. 如果多个trait有同样的父trait,则父trait的构造器只初始化一次
  5. 执行子类构造器
package Trait0

object ClassDemo6 {
  trait Word_Name { // 父特质
    println("---父类:\nfarm n.农场 v.收割 \nhoneydew n.蜜露 \ntechnology n.技术")
  }

  // 创建子特质 Word_Verb,继承 Word_Name
  trait Word_Verb extends Word_Name {
    println("---继承v.:\nWord_Name:yield v.收获;屈服 \nproduce v.生产 \nrethought v.再次思考;再次考虑")
  }

  // 创建子特质 Word_adj,继承 Word_Name
  trait Word_adj extends Word_Name{
    println("---继承adj.:\ntechnological a.技术上的 \ndrastic a.剧烈的 \ndigital a.数字化的")
  }
  // 创建父类 Word:
  class Word{
    println("执行Word构造器")
  }

  class Student extends Word with Word_adj with Word_Verb {
    println("执行Student构造器")
  }

  def main(args: Array[String]): Unit = {
    new Student // 创建 Student对象
  }
}

★ Scala ★——Trait特质大全细则_第6张图片

trait继承class

1 概述
在Scala中, trait(特质)也可以继承class(类)。特质会将class中的成员都继承下来。

class 类A { //类A 
	//成员变量 
	//成员方法 
}

trait B extends A {
 	//特质B 
 }
package Trait0

object ClassDemo7 {
  class Word {
    def printMsg() = println("practice n.实践 address v.解决;强调;演讲")
  }

  trait Log extends Word    // 创建Log特质 继承 Word

  class ConLog extends Log  // 定义ConLog类,继承Log

  def main(args: Array[String]): Unit = {
    val c = new ConLog // 创建ConLog类的对象,并调用printMsg方法
    c.printMsg()
  }
}

★ Scala ★——Trait特质大全细则_第7张图片

你可能感兴趣的:(scala,scala)