★ Scala ★——方法def 与 函数 细则,99乘法表案例实现
★ Scala ★——类和对象(伴生对象)大全细则
★ Scala ★——继承、方法重写、抽象类、匿名类大全细则
★ Scala ★——Trait特质大全细则
★ Scala ★ —— 数据结构(列表、元组、数组)
★ Scala ★ —— 数据结构(集、映射、迭代器)
有些时候, 我们会遇到一些特定的需求, 即: 在不影响当前继承体系的情况下, 对某些类(或者某些对象)的功能进行加强, 例如: 有猴子类和大象类, 它们都有姓名, 年龄, 以及吃的功能, 但是部分的猴子经过马戏团的训练后, 学会了骑独轮车. 那骑独轮车这个功能就不能定义到父类(动物类)或者猴子类中, 而是应该定义到特质中,而Scala中的特质, 要用关键字 trait 修饰。
注意:
- 如果特质中只有抽象内容, 这样的特质叫: 瘦接口
- 如果特质中既有抽象内容, 又有具体内容, 这样的特质叫: 富接口
定义特质:
trait 特质名称 {
// 普通字段
// 抽象字段
// 普通方法
// 抽象方法
}
继承特质:
class 类 extends 特质1 with 特质2 {
// 重写抽象字段
// 重写抽象方法
}
注意
- scala中不管是类还是特质, 继承关系用的都是 extends 关键字。
- 如果要继承多个特质(trait),则特质名之间使用 with 关键字隔开。
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中, 类和特质之间无任何的继承关系, 但是通过特定的关键字, 却可以让该类对象具有指定特质中的成员。
val/var 对象名 = new 类 with 特质
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.喂养;投喂")
}
}
设计模式(Design Pattern) 是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它并不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。
设计模式一共有23种, 分为如下的3类:
创建型
指的是: 需要创建对象的. 常用的模式有: 单例模式, 工厂方法模式。
结构型
指的是: 类,特质之间的关系架构. 常用的模式有: 适配器模式, 装饰模式。
行为型
指的是: 类(或者特质)能够做什么. 常用的模式有:模板方法模式, 职责链模式。
trait 特质A{
// 抽象方法1
// 抽象方法2
// 抽象方法3
//...
}
abstract class 类B extends A{ //适配器类
// 重写抽象方法1, 方法体为空
// 重写抽象方法2, 方法体为空
// 重写抽象方法3, 方法体为空
//...
}
class 自定义类C extends 类B {
// 需要使用哪个方法, 重写哪个方法即可.
}
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()
}
}
在现实生活中, 我们会遇到论文模板, 简历模板, 包括PPT中的一些模板等, 而在面向对象程序设计过程中,程序员常常会遇到这种情况:设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关。
在Scala中, 我们可以先定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤, 这就是: 模板方法设计模式
优点
缺点
类的个数增加, 导致系统更加庞大, 设计也更加抽象。
因为要对每个不同的实现都需要定义一个子类
提高了代码阅读的难度。
父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构
class A {
//父类, 封装的是公共部分
def 方法名(参数列表) = { //具体方法, 在这里也叫: 模板方法
//步骤1, 已知.
//步骤2, 未知, 调用抽象方法
//步骤3, 已知. //步骤n...
}
// 抽象方法
}
class B extends A {
//重写抽象方法
}
注意: 抽象方法的个数要根据具体的需求来定, 并不一定只有一个, 也可以是多个
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()) // 测试执行时间
}
}
1 概述
多个trait中出现了同一个方法, 且该方法最后都调用了super.该方法名(), 当类继承了这多个trait后, 就可以依次调用多个trait中的此同一个方法了, 这就形成了一个调用链。
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.收入")
}
}
每个特质只有 一个无参数 的构造器。也就是说: trait也有构造代码,但和类不一样,特质不能有构造器参数
遇到一个类继承另一个类、以及多个trait的情况,当创建该类的实例时,它的构造器执行顺序如下:
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对象
}
}
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()
}
}