hangscer

Trait和类型转换

2017/02/11

Trait和类型转换

Trait:特质 特点
Trait是可以混入或者融合一个类层次结构的行为(AOP?)。
Trait就像一个拥有部分实现的接口,它提供介于单一继承和多重继承的中间地带。在其他类中混入(max in),用于对类的增强。

单一继承迫使成为线性层次结构。然而,世界充满了横切关注点,安全、日志、校验、事务等等。Scala借用Trait将关注点应用到任意类中。

为Human建模,他可以听listen

1
2
3
4
5
class Human(val name:String){
def listen()=println("Your friend "+name+" is listening")
}
class Man(override val name:String) extends Human(name)
class WoMan(override val name:String) extends Human(name)

以上代码不足之处在于,朋友这方面特性不突出,而且它是混在Human中,如果狗狗是人类朋友——当我们有太多无法释怀时,它们会安静地听我们叙说。

Trait就像部分实现的接口,trait里定义和初始化的val和var会在混入trait的类内部的到实现。而定义未初始化的val和var则认为是抽象的,需要由混入这些trait的类实现。

1
2
3
4
5
6
7
8
trait Friend{
val friend_name:String // abstract
def listen()=println("Your friend "+friend_name+" is listening")
}
class Animal
class Dog(val name:String) extends Animal with Friend
//用with混入,当没有继承其他类时
//也用extends

trait很像类,但是不是。他们需要混入类去实现那些已声明但未初始化(即抽象的)的变量和值。trait会被编译成Java的借口,和对应的实现类(包含了trait实现的方法)。

7.2 选择性混入

上面的例中,trait Friend混入了Dog类中,这样就可以将Dog的任意实例当做Friend,所有的Dog就是Friend

1
2
3
4
5
6
var dog_1:Friend=new Dog("dwqdqwdsaadaadas")//确实用Friend引用了Dog
println(dog_1.friend_name)
///////////////// 对比
var dog_2:Dog=new Dog("dwqdqwdsaadaadas")
println(dog_2.friend_name)
println(dog_2.name) //类型不同 引用的域不同

上面的例子是在类一级混入的,那么是否可以在创建实例时混入呢?
爱喵的人,在创建喵的实例时,为其混入。

1
2
3
4
class Cat() extends Animal
val cat=new Cat() with Friend
//创建实例时混入trait
println(cat.friend_name)

7.3 以trait进行装饰

难 略
设计思想

7.4 trait方法的延迟绑定

略 这里要重点掌握

7.5 隐式类型转换

若:
5 days from_now

2调用了days()方法,传入参数ago,但是Int并没有days()方法,
但是这并不能阻止我们写出这样的代码——进入隐式类型转换的世界吧!!!!
建立一个DateHelper(number:Int)类,其具有days()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class DateHelper(number:Int){
def days(when:String)={
var date=Calendar.getInstance
when match{
case "ago"=>date.add(Calendar.DAY_OF_MONTH, -number)
case "from_now"=>date.add(Calendar.DAY_OF_MONTH, number)
}
date.getTime.toString
}
}
implicit def converInt2DateHelper(number:Int)=new DateHelper(number)
val past=2.days("from_now")
//这这里呢
println(past)

将代码进一步封装,把转换器放入DateHelper的伴生对象中去

可以用一个方法来做这件事,接收一个Int,返回DateHelper的实例,

把方法标记为implicit,只要它在当前范围内存在,Scala会自动调用它。

Predef对象里,Scala已经定义了一些隐式转换,Scala默认导入它们,比如1 to 3,Scala会隐式将1从Int转换为RichInt,调用RichIntto方法。