日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

2021年大数据常用语言Scala(三十一):scala面向对象 特质(trait)

發布時間:2023/11/28 生活经验 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2021年大数据常用语言Scala(三十一):scala面向对象 特质(trait) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

特質(trait)

作為接口使用

定義具體的方法

定義具體方法和抽象方法

定義具體的字段和抽象的字段

實例對象混入trait

trait調用鏈?

trait的構造機制

trait繼承class


特質(trait)

OLTP = online transaction processing

大數據:OLAP = online analysis processing

scala中沒有interfact的接口

可以用trait來實現接口的功能。

同時trait比接口更強大

  • 特質是scala中代碼復用的基礎單元
  • 它可以將方法和字段定義封裝起來,然后添加到類中
  • 與類繼承不一樣的是,類繼承要求每個類都只能繼承一個超類,而一個類可以添加任意數量的特質。
  • 特質的定義和抽象類的定義很像,但它是使用trait關鍵字

1. trait 中可以有 抽象的 也可以有 具體的
2. 一個類可以實現多個trait(通過with關鍵字)
3. 單個對象也可以附件多個trait
4. trait本身也可以繼承其它class
通過這3個特性,我們可以體現出來。trait是一種 代碼復用的最小單元
我們可以將想要的特性功能封裝到trait中
不管是讓class去附加 還是單個對象去附加 都OK
同時附加的數量不受到影響。

接下來,我們就來學習trait的幾種用法。

?

作為接口使用

  • 使用extends來繼承trait(scala不論是類還是特質,都是使用extends關鍵字)
  • 如果要繼承多個trait,則使用with關鍵字

案例1:繼承單個trait

實現步驟:

創建一個Logger特質,添加一個接受一個String類型參數的log抽象方法

創建一個ConsoleLogger類,繼承Logger特質,實現log方法,打印消息

添加main方法,創建ConsoleLogger對象,調用log方法

示例代碼:

trait?Logger {// 抽象方法def?log(msg:String)
}class?ConsoleLogger extends?Logger {override?def?log(msg:?String):?Unit?=?println(msg)
}object?LoggerTrait {def?main(args:?Array[String]):?Unit?=?{val?logger =?new?ConsoleLoggerlogger.log("控制臺日志: 這是一條Log")}
}

?

案例2:繼承多個trait

實現步驟:

在上一個案例的基礎上,創建一個MessageSender特質,添加接受一個String類型參數的send方法

再讓ConsoleLogger實現一個MessageSender特質,并實現它的send方法,打印"發送消息..."

在main中調用,send方法

示例代碼:

trait?Logger {// 抽象方法def?log(msg:String)
}trait?MessageSender {def?send(msg:String)
}class?ConsoleLogger extends?Logger with?MessageSender {override?def?log(msg:?String):?Unit?=?println(msg)override?def?send(msg:?String):?Unit?=?println(s"發送消息:${msg}")
}object?LoggerTrait {def?main(args:?Array[String]):?Unit?=?{val?logger =?new?ConsoleLoggerlogger.log("控制臺日志: 這是一條Log")logger.send("你好!")}
}

?

案例3:object繼承trait

?

實現步驟:

創建一個LoggerForObject特質,添加一個接受一個String類型參數的log抽象方法

創建一個ConsoleLogger的object,實現LoggerForObject特質,實現log方法,打印消息

編寫main方法,調用ConsoleLogger的log方法

?

trait?LoggerForObject {// 抽象方法def?log(msg:String)
}// object也可以繼承trait
object?ConsoleLogger extends?LoggerForObject {override?def?log(msg:?String):?Unit?=?println(s"控制臺信息 $msg")
}object?ObjectTrait {def?main(args:?Array[String]):?Unit?=?{ConsoleLogger.log("程序退出")}
}

?

在trait中可以定義抽象方法,不寫方法體就是抽象方法

和繼承類一樣,使用extends來繼承trait

繼承多個trait,使用with關鍵字

單例對象也可以繼承trait

?

定義具體的方法

和類一樣,trait中還可以定義具體的方法。·

案例:在trait中定義具體方法

實現步驟:

1. 定義一個LoggerDetail特質

- 添加接受一個String類型的log方法,并打印參數

2. 定義一個UserService類,實現LoggerDetail特質

-??添加add方法,調用log方法打印"添加用戶"

3. 添加main方法

- 創建UserService對象實例

- 調用add方法

示例代碼:

trait?LoggerDetail {// 在trait中定義具體方法def?log(msg:String)?=?println(msg)
}class?UserService extends?LoggerDetail {def?add()?=?log("添加用戶")
}object?MethodInTrait {def?main(args:?Array[String]):?Unit?=?{val?userService =?new?UserServiceuserService.add()}
}

?

定義具體方法和抽象方法

?

  • 在trait中,可以混合使用具體方法和抽象方法
  • 使用具體方法依賴于抽象方法,而抽象方法可以放到繼承trait的子類中實現,這種設計方式也稱為模板模式

?

案例:實現一個模板模式

實現步驟:

1. 添加一個LoggerFix特質

?

- 添加一個log抽象方法,接收String參數

- 添加一個info具體方法,接收String參數,調用log方法,參數添加"INFO:"

- 添加一個warn具體方法,接收String參數,調用log方法,參數添加"WARN:"

- 添加一個error具體方法,接收String參數,調用log方法,參數添加"ERROR:"

2. 創建ConsoleLoggerFix類

?

- 實現LoggerFix特質

- 實現log方法,打印參數

3. 添加main方法

?

- 創建ConsoleLoggerFix類對象

- 調用info方法

- 調用warn方法

- 調用error方法

示例代碼:

trait?Logger08 {// 抽象方法def?log(msg:String)// 具體方法(該方法依賴于抽象方法logdef?info(msg:String)?=?log("INFO:"?+?msg)def?warn(msg:String)?=?log("WARN:"?+?msg)def?error(msg:String)?=?log("ERROR:"?+?msg)
}class?ConsoleLogger08 extends?Logger08 {override?def?log(msg:?String):?Unit?=?println(msg)
}object?Trait08 {def?main(args:?Array[String]):?Unit?=?{val?logger08 =?new?ConsoleLogger08logger08.info("這是一條普通信息")logger08.warn("這是一條警告信息")logger08.error("這是一條錯誤信息")}
}

?

定義具體的字段和抽象的字段

  • 在trait中可以定義具體字段和抽象字段
  • 繼承trait的子類自動擁有trait中定義的字段
  • 字段直接被添加到子類中

案例:在trait中定義具體的字段和抽象的字段

實現步驟:

1. 創建LoggerEx特質

- 定義一個sdf具體字段,類型為SimpleDateFormat,用來格式化日志(顯示到時間)

- 創建一個INFO具體字段,類型為String,初始化為:"信息:當前日期"

- 創建一個TYPE抽象字段,類型為String

- 創建一個log抽象方法,參數為String類型

2. 創建ConsoleLoggerEx類

?

- 實現LoggerEx特質

- 實現TYPE抽象字段,初始化為"控制臺"

- 實現log抽象方法,分別打印TYPE字段,INFO字段和參數

3. 添加main方法

?

- 創建ConsoleLoggerEx類對象

- 調用log方法

?

示例代碼:

trait?LoggerEx {// 具體字段val?sdf =?new?SimpleDateFormat("yyyy-MM-dd HH:mm")val?INFO =?"信息:"?+?sdf.format(new?Date)// 抽象字段val?TYPE:String// 抽象方法def?log(msg:String)
}class?ConsoleLoggerEx extends?LoggerEx {// 實現抽象字段override?val?TYPE:?String =?"控制臺"// 實現抽象方法override?def?log(msg:String):?Unit?=?print(s"$TYPE$INFO?$msg")
}object?FieldInTrait {def?main(args:?Array[String]):?Unit?=?{val?logger =?new?ConsoleLoggerExlogger.log("這是一條消息")}
}

?

實例對象混入trait

  • trait還可以混入到實例對象中,給對象實例添加額外的行為
  • 只有混入了trait的對象才具有trait中的方法,其他的類對象不具有trait中的行為
  • 使用with將trait混入到實例對象中

案例:將一個特質混入到一個對象中

實現步驟:

1. 創建一個LoggerMix混入

?

- 添加一個log方法,參數為String類型

- 打印參數

2. 創建一個UserService類

3. 添加main方法

?

- 創建UserService對象,還如LoggerMix特質

- 調用log方法

?

示例代碼:

trait?LoggerMix {def?log(msg:String)?=?println(msg)
}class?UserServiceobject?FixedInClass {def?main(args:?Array[String]):?Unit?=?{// 使用with關鍵字直接將特質混入到對象中val?userService =?new?UserService with?LoggerMixuserService.log("你好")}
}

?

trait調用鏈?

責任鏈模式

?

需求:

?

類繼承了多個trait后,可以依次調用多個trait中的同一個方法,只要讓多個trait中的同一個方法在最后都依次執行super關鍵字即可。類中調用多個tait中都有這個方法時,首先會從最右邊的trait方法開始執行,然后依次往左執行,形成一個調用鏈條。

案例:實現一個模擬支付過程的調用鏈

實現步驟:

1. 定義一個HandlerTrait特質

-?定義一個具體的handler方法,接收String參數,打印"處理數據..."

2. 定義一個DataValidHandlerTrait,繼承HandlerTrait特質

?

- 重寫handler方法

- 打印"驗證數據"

- 調用父特質的handler方法

3. 定義一個SignatureValidHandlerTrait,繼承HandlerTrait特質

?

- 重寫Handler方法

- 打印"檢查簽名"

- 調用父特質的handler方法

4. 創建一個PaymentService類

?

- 繼承DataValidHandlerTrait

- 繼承SignatureValidHandlerTrait

- 定義pay方法

  • 打印"準備支付"
  • 調用父特質的handler方法

5.添加main方法

?

- 創建PaymentService對象實例

- 調用pay方法

?

示例:

// 支付數據處理
trait?HandlerTrait {def?handle(data:?String)?=?{println("處理數據...")}
}// 數據校驗處理
trait?DataValidHandlerTrait extends?HandlerTrait {override?def?handle(data:?String)?=?{println("驗證數據...")super.handle(data)}
}// 簽名校驗處理
trait?SignatureValidHandlerTrait extends?HandlerTrait {override?def?handle(data:?String)?=?{println("檢查簽名...")super.handle(data)}
}// 支付服務
class?PaymentService extends?DataValidHandlerTrait with?SignatureValidHandlerTrait {def?pay(data:String)?=?{println("準備支付...")this.handle(data)}
}object?PaymentService {def?main(args:?Array[String])?{val?payService =?new?PaymentService()payService.pay("signature:10233123||md5:123889a3d5s1f6123||data:{order:001,money:200}")}
}// 程序運行輸出如下:
// 準備支付...
// 檢查簽名...
// 驗證數據...
// 處理數據...

?

trait的構造機制

?

責任鏈模式和類構造順序不同

責任鏈(指的是對父類方法的調用):

  • 從右向左, 同層優先

父類構造順序:

  • 從左到右,父類優先
  • trait也有構造代碼,但和類不一樣,特質不能有構造器參數
  • 每個特質只有一個無參數的構造器。
  • 一個類繼承另一個類、以及多個trait,當創建該類的實例時,它的構造順序如下:
  1. 執行父類的構造器
  2. 從左到右依次執行trait的構造器
  3. 如果trait有父trait,先構造父trait,如果多個trait有同樣的父trait,則只初始化一次
  4. 執行子類構造器

?

案例:演示trait的構造順序

實現步驟:

  1. 創建一個Person_One特質,在構造器中打印"執行Person構造器!"
  2. 創建一個Logger_One特質,在構造器中打印"執行Logger構造器!"
  3. 創建一個MyLoggerOne特質,繼承自LoggerOne特質,,在構造器中打印"執行MyLogger構造器!"
  4. 創建一個TimeLoggerOne特質,繼承自LoggerOne特質,在構造器中打印"執行TimeLogger構造器!"
  5. 創建一個StudentOne類,繼承自PersonOne、MyLoggerOne、TimeLoggerOne特質,在構造器中打印"執行Student構造器!"
  6. 添加main方法,實例化Student_One類,觀察輸出。

?

示例代碼:

?

class?Person_One {println("執行Person構造器!")
}
trait?Logger_One {println("執行Logger構造器!")
}
trait?MyLogger_One extends?Logger_One {println("執行MyLogger構造器!")
}
trait?TimeLogger_One extends?Logger_One {println("執行TimeLogger構造器!")
}
class?Student_One extends?Person_One with?MyLogger_One with?TimeLogger_One {println("執行Student構造器!")}
object?exe_one {def?main(args:?Array[String]):?Unit?=?{val?student =?new?Student_One}
}// 程序運行輸出如下:
// 執行Person構造器!
// 執行Logger構造器!
// 執行MyLogger構造器!
// 執行TimeLogger構造器!
// 執行Student構造器!

?

trait繼承class

  • trait也可以繼承class
  • 這個class就會成為所有該trait子類的超級父類。

單個實例對象附加trait的時候, 無法在任何地方調用trait父類的成員

必須是class繼承trait才可以

案例:定義一個特質,繼承自一個class

?

實現步驟:

1. 創建一個MyUtils類

- 定義printMsg方法,接收String參數,并打印參數

2. 創建一個Logger_Two特質

?

- 繼承自MyUtils

- 定義log方法,接收String參數,并打印一個前綴和參數

3. 創建一個Person_Three類

?

- 實現String類型name字段的主構造器

- 繼承Logger_Two特質

- 實現sayHello方法

  • 調用log,傳入"Hi, I‘m "加上name字段
  • 調用printMsg,傳入"Hello, I'm "加上name字段

4. 添加main方法

?

- 創建一個Person_Three對象

- 調用sayHello方法

?

示例:

class?MyUtil {def?printMsg(msg:?String)?=?println(msg)
}
trait?Logger_Two extends?MyUtil {def?log(msg:?String)?=?this.printMsg("log: "?+?msg)
}
class?Person_Three(val?name:?String)?extends?Logger_Two {def?sayHello {this.log("Hi, I'm "?+?this.name)this.printMsg("Hello, I'm "?+?this.name)}
}
object?Person_Three{def?main(args:?Array[String])?{val?p=new?Person_Three("Tom")p.sayHello//執行結果:
// ?????log: Hi, I'm Tom
// ?????Hello, I'm Tom}
}

?

總結

以上是生活随笔為你收集整理的2021年大数据常用语言Scala(三十一):scala面向对象 特质(trait)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。