Saltar al contenido

Patrones que se Confunden entre Sí

Wrappers, fábricas, algoritmos intercambiables, notificaciones y undo: los cinco grupos de patrones con estructura casi idéntica, y qué pregunta los distingue en cada caso.

7 min. de lectura

Buena parte del catálogo GoF comparte estructura. Cuatro patrones envuelven un objeto y delegan; tres crean objetos detrás de una abstracción; dos delegan comportamiento a un objeto intercambiable. Mirando solo el diagrama de clases, varios son indistinguibles.

Lo que los separa no es la estructura sino la intención: qué problema estaban resolviendo cuando alguien decidió usarlos. Este artículo recorre los cinco grupos donde esa confusión aparece más seguido y da, para cada uno, la pregunta que los desambigua.

Los cuatro wrappers: Adapter, Decorator, Proxy y Facade

Los cuatro reciben un objeto, guardan una referencia y delegan. La diferencia está en qué cambian al delegar.

Patrón¿Cambia la interfaz?¿Cambia el comportamiento?¿Cuántos objetos envuelve?Intención
AdapterNoUnoHacer compatible lo que no lo era
DecoratorNoSí, agregaUnoSumar responsabilidades sin heredar
ProxyNoNo, controla el accesoUnoDecidir si y cuándo se llega al objeto real
FacadeSí, la simplificaNoVariosDar una entrada simple a un subsistema

La pregunta que ordena el grupo:

  • ¿La interfaz de salida es distinta de la de entrada? Si sí, es Adapter o Facade. Si envuelve un objeto para traducirlo, Adapter; si envuelve varios para simplificar, Facade.
  • ¿La interfaz es la misma? Entonces es Decorator o Proxy. Si el wrapper agrega comportamiento observable (un precio extra, un log, una validación), es Decorator. Si el comportamiento es idéntico y lo que el wrapper decide es el acceso (cargar de forma lazy, cachear, verificar permisos, llamar a un objeto remoto), es Proxy.

Las tres fábricas: Factory Method, Abstract Factory y la “Simple Factory”

Este es el grupo donde más se confunde el nombre, en parte porque el tercero no es un patrón GoF.

Qué produceCómo se elige la variante¿Es GoF?
Simple FactoryUn productoUn switch o if dentro de un método estáticoNo, es un idiom
Factory MethodUn productoEligiendo la subclase del creador
Abstract FactoryUna familia de productos compatiblesEligiendo la fábrica concreta

Un método estático con un switch que devuelve new PdfExporter() o new CsvExporter() es útil y perfectamente legítimo, pero no es Factory Method. En Factory Method la decisión está codificada en la jerarquía: cada subclase del creador sabe qué producto le corresponde, y no hay condicional que actualizar al sumar una variante.

La pregunta que ordena el grupo:

  • ¿Cuántos productos relacionados se crean juntos? Si es uno solo, mirá Factory Method. Si son varios que tienen que ser compatibles entre sí (una factura y una etiqueta, ambas del mismo país), es Abstract Factory.
  • ¿La variante se elige extendiendo una clase o con un condicional? Si es un condicional en un solo lugar y no molesta, es una simple factory y está bien. Llamala así.

Delegar comportamiento: Strategy, State y Template Method

Strategy y State tienen diagramas de clases prácticamente idénticos: un contexto con una referencia a una interfaz, y varias implementaciones. Se distinguen por quién decide cuál se usa.

PatrónQuién elige la implementación¿Las implementaciones se conocen?Cuándo cambia
StrategyEl código clienteNo, son independientesCuando el cliente lo decide
StateLos propios estadosSí, cada uno sabe a cuál transicionaComo consecuencia de una operación
Template MethodSe fija al elegir la subclaseIrrelevanteNo cambia en runtime

La pregunta decisiva: ¿una implementación puede reemplazarse a sí misma por otra? Si PaidState decide pasar a ShippedState, es State. Si ExpressShipping no tiene idea de que existe StandardShipping, es Strategy.

La otra distinción, entre los dos primeros y Template Method, es composición contra herencia: Strategy y State se cambian en tiempo de ejecución porque son objetos referenciados; Template Method queda fijo porque la variación se resuelve al instanciar la subclase.

Comunicar cambios: Observer y Mediator

Los dos reducen el acoplamiento entre objetos que necesitan reaccionar unos a otros, y los dos terminan con un objeto central. La diferencia es qué sabe ese objeto central.

  • En Observer el flujo es unidireccional y anónimo: el subject anuncia que algo pasó y no sabe ni le importa quién escucha. Los observers no se conocen entre sí ni coordinan nada. Sumar un observer no cambia el subject.
  • En Mediator el flujo es bidireccional y coordinado: el mediador conoce a todos los colleagues y contiene la lógica de cómo se afectan entre sí. Cuando cambia el método de envío, el mediador decide recalcular el total y deshabilitar el cupón.

La pregunta: ¿el objeto central tiene reglas? Si solo reparte el aviso, es Observer. Si decide qué hacer en función de quién avisó, es Mediator. Un mediator suele usar observer internamente para enterarse de los cambios; son complementarios más que alternativos.

Guardar y deshacer: Command y Memento

Se confunden porque los dos aparecen cuando alguien pide “deshacer”.

  • Command guarda la operación: qué se hizo y con qué argumentos. Deshacer es aplicar la operación inversa. Es eficiente en memoria y permite además encolar, reintentar y loguear.
  • Memento guarda el estado: una foto de cómo estaba el objeto antes. Deshacer es restaurar la foto. Es más simple de escribir correctamente, y más caro si el estado es grande.

En la práctica se combinan: un Command guarda un Memento del estado previo cuando calcular la operación inversa es difícil o imposible.

Cómo usar esta comparación

Ninguna de estas preguntas sirve para decidir qué patrón aplicar a un problema nuevo. Sirven para lo contrario: nombrar correctamente algo que ya escribiste, o entender qué esperaba quien escribió el código que estás leyendo.

Para elegir, el camino sigue siendo el del artículo de introducción: partir del problema concreto, no del catálogo.

Te sirvió, compartilo

// ¿te sirvió?
// compartilo