Y luego de un largo rato volvemos por acá con una historia basada en hechos reales, sobre una conversación muy didáctica que tuve con un amigo:
-Mr. Bladi, he escuchado que Ud. se opone, es más desprecia,
al uso de las clases Utilitarias y los métodos estáticos en la programación
orientada a objetos (OOP).
-Ciertamente. No aconsejo su uso y lo considero una mala
práctica, algo ofensivo en la OOP.
-Pero si no podemos usar clases utilitarias y métodos
estáticos, ¿Cuáles opciones Tenemos?
-Tenemos unas cuantas opciones. Pero antes un poco de contexto.
Las clases utilitarias, esas que están repletas de métodos estáticos, no son
objetos reales, son un recurso totalmente procedimental y rompen el principio
de encapsulamiento en la OOP.
Peor aún, las clases utilitarias con su torrente de métodos estáticos, son muy difíciles de testear en las pruebas automáticas.
Peor aún, las clases utilitarias con su torrente de métodos estáticos, son muy difíciles de testear en las pruebas automáticas.
TODO MÉTODO ESTÁTICO, E INCLUSO LOS PRIVADOS, SON CANDIDATOS
PARA UNA NUEVA CLASE, es decir son elegibles para una nueva abstracción.
Veamos un ejemplo…. Y como siempre nuestro grito de guerra:
Manos a las sobras!!!
Supongamos que tenemos la usual clase:
public class MyMath { public static double sumar(double a, double b) { return a + b; } public static double restar(double a, double b) { return a - b; } public static double multiplicar(double a, double b) { return a * b; } public static double dividir(double a, double b) { return a / b; } }
La cual podemos y solemos utilizar del siguiente modo:
double result = MyMath.sumar(2.0, 3.0); System.out.println(“result = “ + result); System.out.println(“result * 3 + 2 = ” + (MyMath.sumar(MyMath.multiplicar(result, 3.0),2.0)));
Primera implementación:
public interface Operacion{ public double ejecutar(double ope1, double ope2); }
Escribimos clases para cada implementación de Operacion que deseemos:
public final class Sumar implements Operacion { public double ejecutar(double ope1, double ope2){ return ope1 + ope2; } } public final class Multiplicar implements Operacion { public double ejecutar(double ope1, double ope2){ return ope1 * ope2; } }
Y la podemos usar de la siguiente forma:
Operacion sumar = new Sumar(); Operacion multiplicar = new Multiplicar(); double result = sumar.ejecutar(2.0, 3.0); System.out.println(“result = “ + result); System.out.println(“result * 3 + 2 = ” + (sumar.ejecutar(multiplicar.ejecutar(result, 3.0),2.0)));
Así que mejoremos este enfoque.
Segunda implementación:
Ahora la interface Operacion queda de la siguiente forma:public interface Operacion{ public double ejecutar(); }
Mucho mas sencilla. Y ahora sus implementaciones:
public final class Sumar implements Operacion { private double ope1, ope2; public Sumar(double ope1, double ope2){ this.ope1= ope1; this.ope2= ope2; } public double ejecutar(){ return ope1 + ope2; } } public final class Multiplicar implements Operacion { private double ope1, ope2; public Multiplicar(double ope1, double ope2){ this.ope1= ope1; this.ope2= ope2; } public double ejecutar(){ return ope1 * ope2; } }
Como ven, muy parecidas pero con grandes diferencias. Estos si son verdaderos objetos encapsulando comportamiento y datos. Ahora los podemos usar de la siguiente forma:
Operacion sumar = new Sumar(2.0, 3.0); double result = sumar.ejecutar(); System.out.println(“result = “ + result); System.out.println(“result * 3 + 2 = ” + (new Sumar(new Multiplicar(result, 3.0).ejecutar(),2.0).ejecutar()));
Hemos dado un paso al frente en nuestra visión de la programación orientada a objetos. Pero aún lo podemos hacer de forma distinta...
Tercera implementación:
Y… ¿Qué tal si hacemos esto más al estilo “Fluent”? Pues veamos…. Vamos a crear una Interface Operable:
public interface Operable{ public double valor(); public Operable sumar(double operando); public Operable multiplicar(double operando); }
E implementamos la Interface:
public final class Operando implements Operable{ private double valor; public Operando(){ this(0.0); } public Operando(double number){ valor= number; } public double valor(){ return valor; } public Operable sumar(double operando){ return new Operando(this.valor + operando); } public Operable multiplicar(double operando) ){ return new Operando(this.valor * operando); } @overwrite public String toString(){ return “” + valor; } }
Ahora lo podemos usar escribiendo código como el siguiente:
Operando result = new Operando(2.0).sumar(3.0); System.out.println(“result = “ + result); System.out.println(“result * 3 + 2 = ” + result.multiplicar(3.0).sumar(2.0));
Elegante, ¿no les parece? Así que nada de excusas para clases utilitarias y métodos estáticos.
-Mr. Bladi, cuando crezca quiero ser como Ud.
-Lo serás mi pequeño saltamontes. Lo serás...
"una operación entre dos operadores" esto es = a tres ?
ResponderEliminarSi, "=" es una operación, y los valores a su izquierda o derecha serían los operandos u operadores.
Eliminar