Saltar al contenido

Patrones que se Confunden entre Sí

Misma estructura, distinta intención: la pregunta que distingue los pares de patrones que el diagrama de clases no alcanza a separar.

8 min. de lectura

Buena parte del catálogo GoF comparte estructura. Adapter, Decorator y Proxy envuelven un objeto y delegan; Factory Method y Abstract Factory crean objetos detrás de una abstracción; Strategy y State 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. Este artículo recorre los cinco grupos donde esa confusión aparece más seguido y, para cada uno, la pregunta que los desambigua.

Los artículos de cada patrón desarrollan el problema, el código y el cuándo usarlo. Acá el foco es otro: nombrar bien algo que ya está escrito, o entender qué esperaba quien lo escribió.

Wrappers: Adapter, Decorator, Proxy — y Facade

Adapter y Decorator se llaman también Wrapper. Proxy entra en el mismo grupo: los tres reciben un objeto, guardan una referencia y delegan. Facade se cuela en la comparación porque también se interpone delante de otro código, pero no envuelve un objeto: ofrece una entrada simple a un subsistema.

La diferencia entre los tres wrappers está en qué cambian al delegar.

Patrón¿Cambia la interfaz?¿Cambia el comportamiento?¿Cuántos objetos?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 envuelve un objeto para traducirlo, es Adapter. Si concentra varios para simplificar, es Facade.
  • ¿La interfaz es la misma? Entonces es Decorator o Proxy. Si el wrapper agrega comportamiento observable —un cargo extra, un log, una validación—, es Decorator. Si el resultado es el mismo y lo que decide es el acceso —posponer la carga, cachear, verificar permisos, hablar con un objeto remoto—, es Proxy.

Factories: Factory Method, Abstract Factory y 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 recurso habitual
Factory MethodUn productoEligiendo la subclase del Creator
Abstract FactoryUna familia de productos compatiblesEligiendo el factory concreto

Un método estático con un switch que devuelve new PdfExporter() o new CsvExporter() es útil y legítimo, pero no es Factory Method. En Factory Method la decisión está en la jerarquía: cada subclase del creator 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í, es Abstract Factory: un factory por producto no garantiza que no se mezclen familias.
  • ¿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 tiempo de ejecución

La pregunta decisiva: ¿una implementación puede reemplazarse a sí misma por otra? Si el estado actual decide el siguiente, es State. Si el cliente elige el algoritmo y las implementaciones no se conocen entre sí, es Strategy.

La otra distinción, frente a 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: la clase base fija la secuencia y las subclases solo completan los pasos que varían.

Comunicar cambios: Observer y Mediator

Los dos reducen el acoplamiento entre objetos que necesitan reaccionar unos a otros. La diferencia es qué sabe el objeto del medio.

  • En Observer el flujo es unidireccional y anónimo: el sujeto anuncia que algo pasó y no sabe quién escucha. Los observadores no se conocen entre sí ni coordinan nada. Sumar un observador no cambia al sujeto.
  • En Mediator el flujo es bidireccional y coordinado: el mediador conoce a los componentes y contiene las reglas de cómo se afectan. Un cambio en uno puede recalcular otro o deshabilitar un tercero, y esa lógica vive en el mediador, no repartida en referencias cruzadas.

La pregunta: ¿el objeto central tiene reglas? Si solo reparte el aviso, es Observer. Si decide qué hacer según quién avisó, es Mediator. Un mediador 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 más liviano en memoria y además permite encolar, reintentar y loguear.
  • Memento guarda el estado: una foto de cómo estaba el objeto antes, sin exponer sus campos privados. Deshacer es restaurar la foto. Es más simple de escribir bien, y más caro si el estado es grande.

La pregunta: ¿guardás la operación o el estado? Si deshacer es aplicar la inversa —y además querés encolar o loguear—, es Command. Si deshacer es restaurar una foto, es Memento.

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