miércoles, 25 de mayo de 2016

Estructuras inmutables en java


Si bien no es algo super novedoso pero la verdad es que muchos desarrolladores no saben que se puede modelar estructuras inmutables en Java.

En java hay muchas estructuras inmutables podemos pensar en los String, Integer, BigDecimal or BigInteger.

Estas estructuras representan datos que sería impensable que cambie su estado interno. Es decir son objetos que representan un valor. Podemos pensar en el patrón ValueObject que describe Martin Fowler.

Estas estructuras deben devolver una copia de ellos mismos si desean devolver un resultado pero nunca deben cambiar su valor interno.

Pensemos en representar un objeto fracción para esto debemos codificar una clase:

public class Rational {
    private int num;   // the numerator
    private int den;   // the denominator

    // create and initialize a new Rational object
    public Rational(int numerator, int denominator) {
        if (denominator == 0) {
            throw new RuntimeException("Denominator is zero");
        }
        int g = gcd(numerator, denominator);
        num = numerator   / g;
        den = denominator / g;

    }

    // return string representation of (this)
    public String toString() {
        if (den == 1) return num + "";
        else          return num + "/" + den;
    }

    // return (this * b)
    public Rational times(Rational b) {
        return new Rational(this.num * b.num, this.den * b.den);
    }


    // return (this + b)
    public Rational plus(Rational b) {
        int numerator   = (this.num * b.den) + (this.den * b.num);
        int denominator = this.den * b.den;
        return new Rational(numerator, denominator);
    }

    // return (1 / this)
    public Rational reciprocal() { return new Rational(den, num);  }

    // return (this / b)
    public Rational divides(Rational b) {
        return this.times(b.reciprocal());
    }


   /***************************************************************************
    *  Helper functions
    ***************************************************************************/

    // return gcd(m, n)
    private static int gcd(int m, int n) {
        if (0 == n) return m;
        else return gcd(n, m % n);
    }

}

Como se puede ver cada vez que hacemos una operación devolvemos una copia del objeto:

    // return (this + b)
    public Rational plus(Rational b) {
        int numerator   = (this.num * b.den) + (this.den * b.num);
        int denominator = this.den * b.den;
        return new Rational(numerator, denominator);
    }

Esto nos permite no cambiar el estado interno de los objetos.