特质是Scala里代码复用的基础单元。特质封装了方法和字段的定义,并可以通过混入到类中重用它们。
特质的定义除了使用关键字trait之外,与类定义无异。
trait Philosophical {
def philosophize() {
println("I consume memory, therefore I am!")
}
}
使用extends混入特质
class Frog extends Philosophical {
override def toString = "green"
}
//Frog类是AnyRef(Philosophical的超类)的子类并混入Philosophical
//从特质继承的方法可以像从超类继承的方法那样使用
val frog=new Frog
//frog: Frog = green
//Phil的类型是Philosophical,是特质,因此Phil可以被初始化为任何混入了Philosophical特质的类的对象
val phil:Philosophical=frog
//phil: Philosophical = green
frog.philosophize()
//I consume memory, therefore I am!
使用with混入特质
object Ex1 {
class Animal
class Frog extends Animal with Philosophical {
override def toString = "green"
}
def main(args: Array[String]) {
println("new Frog [" + (new Frog) + "]")
}
}
混入多个特质
class Animal
trait HasLegs
class Frog extends Animal with Philosophical with HasLegs {
override def toString = "green"
}
瘦接口对阵胖接口
特质的一种主要应用方式是可以根据类已有的方法自动为类添加方法,即:特质可以丰富一个瘦接口,把它变做胖接口。
object Ex2 {
class Animal
class Frog extends Animal with Philosophical {
override def toString = "green"
override def philosophize() {
println("It ain't easy being "+ toString +"!")
}
}
class Point(x: Int, y: Int)
trait CharSequence {
def charAt(index: Int): Char
def length: Int
def subSequence(start: Int, end: Int): CharSequence
def toString(): String
}
trait Ordered[T] {
def compare(that: T): Int
def <(that: T): Boolean = (this compare that) < 0
def >(that: T): Boolean = (this compare that) > 0
def <=(that: T): Boolean = (this compare that) <= 0
def >=(that: T): Boolean = (this compare that) >= 0
}
import scala.collection.mutable.ArrayBuffer
class BasicIntQueue extends IntQueue {
private val buf = new ArrayBuffer[Int]
def get() = buf.remove(0)
def put(x: Int) { buf += x }
}
trait Incrementing extends IntQueue {
abstract override def put(x: Int) { super.put(x + 1) }
}
trait Doubling extends IntQueue {
abstract override def put(x: Int) { super.put(2 * x) }
}
def main(args: Array[String]) {
(new Frog).philosophize()
// Multiple inheritance thought experiment
val q = new BasicIntQueue with Incrementing with Doubling
q.put(42) // which put would be called?
println("q [" + q + "]")
}
}
长方形对象
class Point(val x: Int, val y: Int)
class Rectangle(val topLeft: Point, val bottomRight: Point) {
def left = topLeft.x
def right = bottomRight.x
def width = right - left
}
abstract class Component {
def topLeft: Point
def bottomRight: Point
def left = topLeft.x
def right = bottomRight.x
def width = right - left
}
trait Rectangular {
def topLeft: Point
def bottomRight: Point
def left = topLeft.x
def right = bottomRight.x
def width = right - left
}
class Rectangle(val topLeft: Point, val bottomRight: Point)
extends Rectangular {
}
val rect = new Rectangle(new Point(1, 1),new Point(10, 10))
//rect: Rectangle = Rectangle@5128197f
rect.left
//res2: Int = 1
rect.right
//res3: Int = 10
rect.width
//res4: Int = 9
ordered 特质
//定义胖接口,4个比较操作符<、>、<=、>=
class Rational(n: Int, d: Int) {
def < (that: Rational) =
this.numer * that.denom > that.numer * this.denom
def > (that: Rational) = that < this
def <= (that: Rational) = (this < that) || (this == that)
def >= (that: Rational) = (this > that) || (this == that)
}
//使用ordered特质为Rational定义比较操作
//首先用一个compare方法替换所有独立的比较方法,ordered特质会利用这个方法定义<、>、<=、>=
class Rational(n: Int, d: Int) extends Ordered[Rational] {
def compare(that: Rational) =
(this.numer * that.denom) - (that.numer * this.denom)
require(d != 0)
private val g = gcd(n.abs, d.abs)
val numer = n / g
val denom = d / g
def this(n: Int) = this(n, 1)
def + (that: Rational): Rational =
new Rational(
numer * that.denom + that.numer * denom,
denom * that.denom
)
def + (i: Int): Rational =
new Rational(numer + i * denom, denom)
def - (that: Rational): Rational =
new Rational(
numer * that.denom - that.numer * denom,
denom * that.denom
)
def - (i: Int): Rational =
new Rational(numer - i * denom, denom)
def * (that: Rational): Rational =
new Rational(numer * that.numer, denom * that.denom)
def * (i: Int): Rational =
new Rational(numer * i, denom)
def / (that: Rational): Rational =
new Rational(numer * that.denom, denom * that.numer)
def / (i: Int): Rational =
new Rational(numer, denom * i)
override def toString = numer +"/"+ denom
private def gcd(a: Int, b: Int): Int =
if (b == 0) a else gcd(b, a % b)
override def equals(other: Any): Boolean =
other match {
case that: Rational =>
(that canEqual this) &&
numer == that.numer &&
denom == that.denom
case _ => false
}
def canEqual(other: Any): Boolean =
other.isInstanceOf[Rational]
override def hashCode: Int =
41 * (
41 + numer
) + denom
}
特质用来做可堆叠的改变
//IntQueue有一个put方法把整数添加到队列中,和get方法移除并返回它们
abstract class IntQueue {
def get(): Int
def put(x: Int)
}
object Ex2 {
class Animal
class Frog extends Animal with Philosophical {
override def toString = "green"
override def philosophize() {
println("It ain't easy being "+ toString +"!")
}
}
class Point(x: Int, y: Int)
trait CharSequence {
def charAt(index: Int): Char
def length: Int
def subSequence(start: Int, end: Int): CharSequence
def toString(): String
}
trait Ordered[T] {
def compare(that: T): Int
def <(that: T): Boolean = (this compare that) < 0
def >(that: T): Boolean = (this compare that) > 0
def <=(that: T): Boolean = (this compare that) <= 0
def >=(that: T): Boolean = (this compare that) >= 0
}
import scala.collection.mutable.ArrayBuffer
//使用ArrayBuffer实现BasicIntQueue
class BasicIntQueue extends IntQueue {
private val buf = new ArrayBuffer[Int]
def get() = buf.remove(0)
def put(x: Int) { buf += x }
}
val queue = new BasicIntQueue
//queue: BasicIntQueue = BasicIntQueue@3e1c58c9
queue.put(10)
queue.put(20)
queue.get()
//res17: Int = 10
queue.get()
//res18: Int = 20
//可堆叠改动特质Incrementing和 Filtering
trait Incrementing extends IntQueue {
abstract override def put(x: Int) { super.put(x + 1) }
}
trait Filtering extends IntQueue {
abstract override def put(x: Int) {
if (x >= 0) super.put(x)
}
}
//混入的次序非常重要
//Doubling可堆叠改动特质
trait Doubling extends IntQueue {
abstract override def put(x: Int) { super.put(2 * x) }
}
def main(args: Array[String]) {
(new Frog).philosophize()
// 多重继承思考实验
val q = new BasicIntQueue with Incrementing with Doubling
q.put(42) // 调用哪个put
println("q [" + q + "]")
}
}
网友评论