SOLID + IntelliJ IDEA

De los tan famosos principios SOLID hay 2 que quiero tratar:

– S de Single Responsibility Principle

Nos recuerda que mantengamos las work units (para mí son las clases) con una única responsabilidad. Este concepto puede sonar un poco abstracto y yo pienso en responsabilidad como motivos para cambiar. En cuanto me huelo que el código que estoy escribiendo va a ser extendido más adelante, trato de separarlo de lo que ya conozco (que no se modifica con demasiada frecuencia).

– I de Interface Segregation

Nos recuerda que mantengamos las interfaces con el menor número de métodos posible ya que quien extiende/herede está obligado a implementarlos todos. Así, los métodos tienen que ser muy cohesivos entre sí y, por supuesto, las interfaces más bonitas son las @FunctionalInterface.

Ahora bien, partirse el pecho por estos principios es duro y cansa. La mayoría del tiempo uno va con tanta prisa que extender código significa escribir más abajo de la clase sin pararse a pensar que quizás vaya siendo hora de trocear.

Afortunadamente el IDE es nuestro amigo y podemos reducir mucho el esfuerzo utilizando la opción de refactorizacion Delegate (en IDEA) que no es más que crear un delegado dueño del código que se quiere sacar de la clase.

El ejemplo -más tonto imposible- es una clase CalculatorImpl con los métodos add() y multiply(). Intuimos que el método add() va a crecer, va a ganar importancia por sí solo y puede que se reutilice en otra parte del código. Motivos suficientes para extraerlo a una clase Adder.

public class CalculatorImpl implements Calculator {

    @Override
    public Long add(Long a, Long b) {
        return a + b;
    }

    @Override
    public Long multiply(Long a, Long b) {
        long product = a;
        for (int i = 1; i < b; i++) {
            product = add(product, a);
        }
        return product;
    }
}

Paso 1: Ctrl + T > Delegate… y escribimos el nombre de la nueva clase: AdderImpl.

  • El método en rojo indica que depende del método toBeSubtracted() y es necesario llevarlo también a la clase AdderImpl por lo que lo marcamos. En caso de no hacerlo, el delegado incluiría un campo de tipo CalculatorImpl para acceder al método.
  • El método en color azul indica que sus dependencias están satisfechas y que su código se modifica referenciando a la nueva clase AdderImpl.
  • La dependencia en campos estáticos no está analizada pero como sabemos que el método add() depende de toBeAdded lo marcamos para que lo mueva.

Ventana Delegate... de IntelliJ

Paso 2: Eliminamos el método toBeSubtracted() que no se ha eliminado de la clase CalculatorImpl.

Paso 3: Corregimos el error que se marca en @Override de AdderImpl con la opción Extract method ‘add’ to new interface y creamos la interface Adder.

Paso 4: Sobre AdderImpl Ctrl + T > Use Interface Where Possible para que la referencia en CalculatorImpl sea a la interfaz Adder. De paso, renombramos el campo con Shift + F6 a adder.

public class CalculatorImpl implements Calculator {

    private final Adder adder = new AdderImpl();

    @Override
    public Long add(Long a, Long b) {
        return adder.add(a, b);
    }

    @Override
    public Long multiply(Long a, Long b) {
        long product = a;
        for (int i = 1; i < b; i++) {
            product = adder.add(product, a);
        }
        return product;
    }
}

La magia definitiva sería que se pudiese implementar una interfaz directamente al delegar uniendo los pasos 1 y 4. Pero lo mismo es demasiado pedir…

Deja un comentario