Functional Objects

1 Immutable Object Trade-Offs

优点:

  • Easier to reason about than mutable ones
  • You can pass immutable objects around quite freely, whereas you may need to make defensive copies of mutable objects before passing them to other code.
  • There is no way for wto thread concurrently accessing an immutable to corrupt its state once it has been properly constructed.
  • Immutable objects make safe hash table keys.

缺点:

  • They sometimes require that a large object graph be copied, where as an update could be done in its place. In some cases this can be awkward to express and might also cause a preformance bottleneck.

2 Re-Implenmenting the tostring method

class Rational(n: Int, d: Int) {
    override def toString = n + "/" + d
}

3 Checking preconditions

class Rational(n: Int, d: Int) {
    require(d != 0)
    override def toString = n + "/" + d
}

4 添加字段

class Rational(n: Int, d: Int) { // This won't compile
    require(d != 0)

    override def toString = n + "/" + d

    def add(that: Rational): Rational = 
        new Rational(n * that.d + that.n * d, d * that.d)
}

Although class parameters n and d are in scope in the code of you add method, you can only access their value on the object on which add was invoked. Thus, when you say n or d in add's implementation, the compiler is happy to provide you with the values for these class parameters. But it won't let you say that.n or that.d because that does not refer to the Rationalobject on which add was invoked. To access the numerator and denominator on that, you'll need to make them into fields:

class Rational(n: Int, d: Int) { // This won't compile
    require(d != 0)

    val number: Int = n
    val denom: Int = d

    override def toString = number + "/" + denom

    def add(that: Rational): Rational = 
        new Rational(number * that.denom + that.number * denom, denom * that.denom)
}

5 Self References

def lessThan(that: Rational) = 
    this.number * that.denom < that.number * this.denom
def max(that: Rational) = 
    if (this.lessThan(that)) that else this

6 Auxiliary Constructors (辅助构造器)

class Rational(n: Int, d: Int) { // This won't compile
    require(d != 0)

    val number: Int = n
    val denom: Int = d

    def this(n: Int) = this(n, 1) // auxiliary constructor

    override def toString = number + "/" + denom

    def add(that: Rational): Rational = 
        new Rational(number * that.denom + that.number * denom, denom * that.denom)
}

7 Rational with a private field and method

class Rational(n: Int, d: Int) { // This won't compile
    require(d != 0)

    private val g = gcd(n.abs, d.abs)
    val number: Int = n / g
    val denom: Int = d / g

    def this(n: Int) = this(n, 1) // auxiliary constructor

    override def toString = number + "/" + denom

    def add(that: Rational): Rational = 
        new Rational(number * that.denom + that.number * denom, denom * that.denom)

    private def gcd(a: Int, b: Int): Int = 
        if (b == 0) a else gcd(b, a % b)
}

8 Defining Operators

class Rational(n: Int, d: Int) { // This won't compile
    require(d != 0)

    private val g = gcd(n.abs, d.abs)
    val number: Int = n / g
    val denom: Int = d / g

    def this(n: Int) = this(n, 1) // auxiliary constructor

    override def toString = number + "/" + denom

    def + (that: Rational): Rational = 
        new Rational(number * that.denom + that.number * denom, denom * that.denom)

    def * (that: Rational): Rational = 
        new Rational(number * that.number, denom * that.denom)

    private def gcd(a: Int, b: Int): Int = 
        if (b == 0) a else gcd(b, a % b)
}

9 Method Overloading

class Rational(n: Int, d: Int) { // This won't compile
    require(d != 0)

    private val g = gcd(n.abs, d.abs)
    val number: Int = n / g
    val denom: Int = d / g

    def this(n: Int) = this(n, 1) // auxiliary constructor

    override def toString = number + "/" + denom

    def + (that: Rational): Rational = 
        new Rational(number * that.denom + that.number * denom, denom * that.denom)

    def * (that: Rational): Rational = 
        new Rational(number * that.number, denom * that.denom)

    def * (i: Int): Rational = 
        new Rational(number * i, denom)

    private def gcd(a: Int, b: Int): Int = 
        if (b == 0) a else gcd(b, a % b)
}

10 Implicit Conversions

scala> 2 * r // error

scala> implcit def intToRational(x: Int) = new Rational(x)
scala> val r = new Rational(2, 3)
scala> 2 * r

results matching ""

    No results matching ""