Scala OOP 基础六

2017/08/12 Scala

Scala OOP 基础知识六

trait 成员

可以在trait中声明抽象成员(字段,方法和类型),但是在创建实例前,继承的类必须定义这些抽象成员。

override

如果子类覆写了父类的方法,override是可以省略的,如果没有覆写,却用了这一关键字,编译器会报错的。 强制使用这个关键字有下列好处:

  1. 有些成员应该被覆写,使用override可以避免犯错。
  2. 向基类中添加新的成员时,基类可以会和子类中成员名称重复,此时会避免产生意料之外的覆写。基类引入这个新成员的时候,编译器会报错的。

    避免覆写具体成员

    使用模版方法模式 (template method pattern),可以减少对于子类覆写父类的场景。如:

case class Address(city: String, state: String, zip: String)
case class Employee(name: String, salary: Double, address: Address)

abstract class Payroll {
def netPay(employee: Employee): Double = { 
	val fedTaxes = calcFedTaxes(employee.salary)
	val stateTaxes = calcStateTaxes(employee.salary, employee.address)
		employee.salary - fedTaxes - stateTaxes
	}

def calcFedTaxes(salary: Double): Double
def calcStateTaxes(salary: Double, address: Address): Double

}

object Payroll2014 extends Payroll { 
	val stateRate = Map(
		"XX" -> 0.05, 
		"YY" -> 0.03, 
		"ZZ" -> 0.0)
	override def calcFedTaxes(salary: Double): Double = salary * 0.25
	override def calcStateTaxes(salary: Double, address: Address): Double = {
		salary * stateRate(address.state) 
	}	

}

val tom = Employee("Tom Jones", 100000.0, Address("MyTown", "XX", "12345")) 
val jane = Employee("Jane Doe", 110000.0, Address("BigCity", "YY", "67890"))

Payroll2014.netPay(tom) 	// Result: 70000.0 
Payroll2014.netPay(jane) 	// Result: 79200.0

定义规则,将具体的实现交给抽象方法完成。抽象类在实例化的时候,会实现出来,这样就可以避免覆写具体成员。

final 声明不允许覆写

class NotFixed {
final def fixedMethod = "fixed"

}
class Changeable2 extends NotFixed { 
	override def fixedMethod = "not fixed" //compiler error
}

线性继承结构

scala使用单继承模型,所以会有引入多个trait的情况,如:

class C1 {
def m = print("C1 ")
}
trait T1 extends C1 {
override def m = { 
	print("T1 "); super.m }
}
trait T2 extends C1 {
override def m = { 
	print("T2 "); super.m }
}
trait T3 extends C1 {
override def m = { 
	print("T3 "); super.m }
}
class C2 extends T1 with T2 with T3 { 
	override def m = { print("C2 "); super.m }
}

val c2 = new C2 c2.m
c2.m		//output : C2 T3 T2 T1 C1

关于多个trait混入,处理原则如下:

  1. 当前实例的具体类型会被放到线性化后的首个元素位置处。
  2. 按照该实例父类型的顺序从右到左的放置节点,针对每个父类型执行线性化算法,并将执行结果合并。(我们暂且不对 AnyRef 和 Any 类型进行处理。)
  3. 按照从左到右的顺序,对类型节点进行检查,如果类型节点在该节点右边出现过,那么便将该类型移除。
  4. 在类型线性化层次结构末尾处添加 AnyRef 和 Any 类型。 如果是对value class执行线性化算法,请使用 AnyVal 类型替代 AnyRef 类型。

小结

OOP部分到这个地方就告一个段落了,接下来介绍下scala的库,毕竟工作中不能什么都自己造轮子。

Show Disqus Comments

Search

    Table of Contents