Extender comportamiento sin modificar código ya probado en producción
Los artefactos de software deben estar abiertos para su extensión y cerrados para su modificación: puedes añadir nuevos comportamientos ampliando el sistema (p. ej. nuevas implementaciones o plugins) sin alterar el código fuente de los módulos existentes que ya funcionan.
Bertrand Meyer acuñó el principio; en OO suele materializarse con abstracciones estables (interfaces o clases base) y nuevas clases concretas que las implementan.
Cada vez que añades un if o un case central que crece con cada regla de negocio nuevo, modificas un módulo compartido y aumentas el riesgo de regresiones. El OCP empuja a modelar variaciones como tipos intercambiables detrás de una misma operación (estrategia, cadena de responsabilidad, etc.).
Cálculo de subtotales en una cesta: cada nuevo tipo de línea (envío, suscripción, bundle) obliga a editar el mismo método.
public final class CartSubtotalCalculator { public Money subtotal(CartLine line) { return switch (line.type()) { case PRODUCT -> line.unitPrice().multiply(line.quantity()); case SHIPPING_FEE -> line.flatFee(); case SUBSCRIPTION -> line.periodPrice(); // añadido después // mañana: GIFT_WRAP -> hay que tocar OTRA VEZ esta clase default -> throw new IllegalStateException("tipo desconocido"); }; } }
Cada tipo de línea aporta su propia estrategia; el calculador solo delega en el contrato CartLine.
public interface CartLine { Money addTo(Money accumulator); } public final class ProductLine implements CartLine { private final Money unitPrice; private final int qty; // ... @Override public Money addTo(Money acc) { return acc.add(unitPrice.multiply(qty)); } } public final class ShippingFeeLine implements CartLine { private final Money flatFee; @Override public Money addTo(Money acc) { return acc.add(flatFee); } } public final class CartSubtotalCalculator { public Money subtotal(List<CartLine> lines) { return lines.stream() .reduce(Money.zero(), (acc, line) -> line.addTo(acc), Money::add); } }
Una línea GiftWrapLine nueva es solo otra clase que implementa CartLine; el calculador cerrado no se recompila por ese motivo.
if simple puede bastar cuando no hay variación esperada.