六狼论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博账号登陆

只需一步,快速开始

搜索
查看: 312|回复: 0

Scala概述(六)合成

[复制链接]

升级  54%

7

主题

7

主题

7

主题

童生

Rank: 1

积分
27
 楼主| 发表于 2013-2-5 02:43:05 | 显示全部楼层 |阅读模式
6.       合成(composition

解释了Scala的类型抽象体系之后,本节主要描述类的合成方式(译注:class composition似乎也没有固定的译法,此处翻译成“合成”)。Scala的基于混入的类合成(mixin class composition)体系是Brach[6]中的面向对象的线性混入合成(linear mixin compostion)和[14、25]中提出的更加对称的混入模块(mixin modules),以及traits[42]这三者的融合。(注:mixin有些人翻译成混合,有些人翻译成混入)我们先看一个例子,如下这个迭代器的抽象描述:
trait AbsIterator[T] {

def hasNext: boolean

def next: T

}
注意上面出现的关键字trait。Trait是一种特殊的抽象类,他的构造子没有任何值参数。Traits可以出现任何抽象类可以出现的地方,但反之不然,只有traits可以用于混入。
下面,我们用一个trait继承自AbsIterator,并增加一个方法foreach,用于将一个函数作用于该迭代子返回的每一个元素上。
trait RichIterator[T] extends AbsIterator[T] {

def foreach(f: T => unit): unit =

while (hasNext) f(next)

}
下面是一个具体的迭代子类定义,用于连续返回一个字符串的每一个字符:
class StringIterator(s: String) extends AbsIterator[char] {

private var i = 0

def hasNext = i < s.length

def next = { val x = s charAt i; i = i + 1; x }

}
 
混入式类合成(Mixin-class composition)下面我们将RichIterator和StringIterator的功能合并在一个类中。只有单根继承和接口的情况下这是不可能的,因为这两个类都有具体的实现代码。因此,Scala提供了混入式类合成的机制,使程序设计者可以重用一个类的增量内容,也就是非继承的内容。这种机制使人可以将RichIterator和StringIterator合并,在如下所示的例子将一个字符串的所有字母打成一列。
object Test {

def main(args: Array[String]): unit = {

class Iter extends StringIterator(args(0))

with RichIterator[char]

val iter = new Iter

iter foreach System.out.println

}

}
Iter类通过RichIterator和StringIterator这两个父类型混入合成,第一个父类型仍然称为超类(superclass),第二个父类型则称为混入(mixin)。
 
类的全序化(Class Linearization)
混入式类合成是多重继承的一种形式,因此也会面临单继承所没有的问题。最典型的就是:如果多个父类型定义了同名的成员,哪一个成员被继承?调用父类方法时那一个成员被引用?如果一个类从多个路径被继承了怎么办?在Scala中,解决这些问题的基础构造就是类的全序化(class linearization)。(注:linearization可以翻成线性化或者全序化,在计算机领域一般取后者。另外,后面大部分情况下用全序来替代,主要是为了读起来不那么别扭)
一个类C所直接继承的类形成的可递闭包当中所有类称为C的基类(base classes)。由于有混入类,一个类与它的基类之间的继承关系,构成一个有向无环图(directed acyclic graph)。C的全序化L(C)是C的所有基类的一个全序(total order),根据如下规则构成:假设C的定义为:
class C extends B0 with . . . with Bn { . . . } .
这个全序以C的基类B0的全序为最后一部分,前面是B1的全序(排除掉已经包含在B0的全序当中的类),再前面是B2,…Bn,同样排除掉前面已经出现过的类。最前面的是类C本身,作为这个全序的头一个类。例如,Iter类的全序化是:
{Iter, RichIterator, StringIterator, AbsIterator, AnyRef, Any }

类的全序对于类的继承关系而言是一种改进:如果一个类C是D的子类,则在任何同时继承C、D的类的全序中,C永远出现在D之前。全序化还满足另一个性质:一个类的全序永远包括其基类的全序作为后缀。例如,StringIterator的全序化:{ StringIterator, AbsIterator, AnyRef, Any }就是其子类Iter的全序的后缀。不过对于混入类,这个性质并不成立,一个混入类的全序当中的类,在其子类的全序当中可能以不同的顺序出现,也就是说,Scala中全序化不是单调(monotonic[1])的。
您需要登录后才可以回帖 登录 | 立即注册 新浪微博账号登陆

本版积分规则

快速回复 返回顶部 返回列表