Oportunidades perdidas del Polimorfismo
Autor: Kirk Pepperdine

El polimorfismo es una de las grandes ideas fundamentales de la Orientación a Objetos (OO). La palabra, tomada del griego, significa muchas (poli) formas (morfos). En el contexto de programación el polimorfismo se refiere a las muchas formas de una clase particular de objetos o métodos. Pero el polimorfismo no es simplemente sobre implementaciones alternativas. Usado con cuidado, crea diminutos contextos de ejecución que nos dejan trabajar sin la necesidad de detallados bloques if-then-else. Estar en un contexto nos permite hacer lo correcto directamente, mientras que estar fuera del contexto nos obliga a reconstruirlo para entonces poder hacer lo correcto. Con el uso cuidadoso de implementaciones alternadas podemos capturar el contexto que nos ayude a producir menos código que sea más leíble. Esto se demuestra mejor con algo de código, como el siguiente (e irreal) carrito de compras:

public class ShoppingCart {
    private ArrayList<Item> cart = new ArrayList<Item>();
    public void add(Item item) { cart.add(item); }
    public Item takeNext() { return cart.remove(0);  }
    public boolean isEmpty() { return cart.isEmpty(); }
}

Digamos que nuestra compra en línea ofrece elementos que pueden ser descargados y elementos que necesitan ser enviados. Vamos a construir otro objeto que soporte estas operaciones:

public class Shipping {
    public boolean ship(Item item, SurfaceAddress address) { ... }
    public boolean ship(Item item, EMailAddress address { ... }
}

Cuando un cliente ha completado la compra, necesitamos enviar los bienes:

while (!cart.isEmpty()) {
    shipping.ship(cart.takeNext(), ???);
}

El parámetro ??? no es algún nuevo operador Elvis, está preguntado si debería enviar correo electrónico o correo normal. El contexto necesario para responder la pregunta ya no existe. Pudimos haber capturado el método de envío en un boleano o en un enum y entonces usar un if-then- else para llenar el parámetro faltante. Otra solución sería crear dos clases, en las cuales ambas extiendan Item. Llamémosle DownloableItem y SurfaceItem.Ahora vamos a escribir algo de código. Promoveré Item para que sea una interfaz que soporte un único método: ship. Para enviar el contenido del carrito haremos una llamada a item.ship(shipper). Ambas clases DownloadbleItem y SurfaceItem implementarán ship.

public class DownloadableItem implements Item {
    public boolean ship(Shipping shipper) {
        shipper.ship(this, customer.getEmailAddress());
    }
}

public class SurfaceItem implements Item {
    public boolean ship(Shipping shipper) {
        shipper.ship(this, customer.getSurfaceAddress());
    }
}

En este ejemplo hemos delegado la responsabilidad de trabajar con Shipping en cada Item. Debido a que cada item sabe cómo es mejor que sea enviado, este arreglo nos permite estar con él sin la necesidad de un if-then-else. El código también demuestra un uso de dos patrones que frecuentemente actúan juntos: Command y Double Dispatch. El uso efectivo de estos patrones reside en un uso cuidadoso del polimorfismo. Cuando esto suceda habrá una reducción del número de bloques if-then-else en nuestro código.

Si bien hay casos en los que es mucho más práctico utilizar if-then- else en vez del polimorfismo, es más frecuente el caso en el cual un estilo de código más polimórfico dará lugar a un código base más pequeño, más fácil de leer y menos frágil. El número de oportunidades perdidas es un simple conteo de declaraciones if-then-else en nuestro código.

Traducción: Espartaco Palma

Leer contribución original