函数式对象
以Rational类为例,以下介绍类参数、构造方法、方法、操作符、私有成员、重写、前置条件检查、重载以及自引用。
不可变对象和可变对象的区别
不可变对象通常比可变对象更容易推理,没有随着时间变化而变化,没有复杂的状态空间。其次,可以自由传递不可变对象。而对于可变对象,在传递之前,需要做保护式的拷贝。不可变对象可以安全地用作哈希表的键。
劣势是不可变对象需要一个大的对象图。
构造Rational类
class Rational(n : Int, d : Int)
可以发现和Java有所不同,其类就能接收参数。而在Java中得有构造方法,构造方法接收参数。
重写实现toString方法
可以通过给Rational类添加toString方法来重写默认的实现。
class Rational(n:Int,d:ing) {
override def toString = n + "/" + d
}
检查前置条件
对于不可变对象,要确保对象在构建时的合法性。比如有理数不能分母为0。当传入参数d为0时,应该禁止生成对象。
解决这个问题是对主构造方法定义一个前置条件。
class Rational (n : Int, d : Int) {
required(d != 0)
override def toString = n + "/" + d
}
require方法接收一个boolean参数,传入true,正常返回,传入false,跑出IllegalArgumentException异常
添加字段
定义一个add方法,接收另一个Rational类,为了保持不可变特性,add方法必须创建另一个Rational类,等于这两个Rational类的和。
class Rational (n : Int, d : Int) {
required(d != 0)
val numer:Int = n
val denom:Int = d
override def toString = n + "/" + d
def add(that : Rational) : Rational =
new Rational(
numer * that.denom + that.numer * denom,
denom * that.denom
)
}
不允许使用that.n和that.d来实现。要访问that的分子和分母,要把它们做成字段。
构造方法
某个类定义多个构造方法。在Scala中,主构造方法之外的构造方法称为辅助构造方法。
比如Rational类只接收一个参数,即分子。分母被预定义为1.
//使用this,即类的主构造方法。
def this(n:Int) = this(n,1)
私有字段和方法
比如对Rational类做正规化,要分子和分母除以最大公约数。
class Rational (n : Int, d : Int) {
required(d != 0)
private val g = gcd(n.abs, d.abs)
val numer:Int = n / g
val denom:Int = d / g
def this(n:Int) = this(n,1)
override def toString = n + "/" + d
def add(that : Rational) : Rational =
new Rational(
numer * that.denom + that.numer * denom,
denom * that.denom
)
private def gcd(a:Int, b:Int) : Int =
if (b==0) a else gcd(b, a % b)
}
定义操作符
将x.add(y)转为x+y。
//加法
def + (that: Rational):Rational =
new Rational(
numer * that.denom + that.numer * denom,
denom * that.denom
)
//乘法
def * (that: Rational):Rational =
new Rational(
numer * that.numer,
denom * that.denom
)
方法重载
以+为例,右操作元,可能是有理数,也有可能是整数
def + (that: Rational):Rational =
new Rational(
numer * that.denom + that.numer * denom,
denom * that.denom
)
def + (i: Int) =
new Rational(numer + i * denom, denom)