Estaba leyendo un artículo de programación y mencionaba el patrón Decorador. He estado programando durante un tiempo pero sin ningún tipo de educación o capacitación formal, pero estoy tratando de aprender sobre los patrones estándar y demás.
Entonces busqué el Decorador y encontré un artículo de Wikipedia sobre él. Ahora entiendo el concepto del patrón Decorador, pero este pasaje me confundió un poco:
Como ejemplo, considere una ventana en un sistema de ventanas. Para permitir el desplazamiento del contenido de la ventana, podemos agregarle barras de desplazamiento horizontales o verticales, según corresponda. Suponga que las ventanas están representadas por instancias de la clase Window, y suponga que esta clase no tiene funcionalidad para agregar barras de desplazamiento. Podríamos crear una subclase ScrollingWindow que los proporcione, o podríamos crear un ScrollingWindowDecorator que agregue esta funcionalidad a los objetos de Windows existentes. En este punto, cualquier solución estaría bien.
Ahora supongamos que también deseamos la posibilidad de agregar bordes a nuestras ventanas. Nuevamente, nuestra clase de ventana original no tiene soporte. La subclase ScrollingWindow ahora plantea un problema, porque efectivamente ha creado un nuevo tipo de ventana. Si deseamos agregar soporte de borde a todas las ventanas, debemos crear subclases WindowWithBorder y ScrollingWindowWithBorder. Obviamente, este problema empeora con cada nueva característica que se agrega. Para la solución de decorador, simplemente creamos un nuevo BorderedWindowDecorator; en tiempo de ejecución, podemos decorar ventanas existentes con ScrollingWindowDecorator o BorderedWindowDecorator o ambos, según lo creamos conveniente.
OK, cuando dicen agregar bordes a todas las ventanas, ¿por qué no simplemente agregar funcionalidad a la clase de ventana original para permitir la opción? A mi modo de ver, la subclasificación es solo para agregar una funcionalidad específica a una clase o anular un método de clase. Si necesito agregar funcionalidad a todos los objetos existentes, ¿por qué no modificaría la superclase para hacerlo?
Había otra línea en el artículo:
El patrón decorador es una alternativa a la subclase. La subclasificación agrega comportamiento en tiempo de compilación, y el cambio afecta a todas las instancias de la clase original; la decoración puede proporcionar un nuevo comportamiento en tiempo de ejecución para objetos individuales.
No entiendo donde dicen "... el cambio afecta a todas las instancias de la clase original": ¿cómo cambia la subclase la clase principal? ¿No es ese el objetivo de la subclase?
Asumiré que el artículo, como muchos Wiki, simplemente no está escrito claramente. Puedo ver la utilidad del Decorador en esa última línea: "... proporcionar un nuevo comportamiento en tiempo de ejecución para objetos individuales".
Sin haber leído sobre este patrón, si tuviera que cambiar el comportamiento en tiempo de ejecución para objetos individuales, probablemente habría incorporado algunos métodos en la superclase o subclase para habilitar / deshabilitar dicho comportamiento. Por favor, ayúdame a comprender realmente la utilidad del Decorador, y ¿por qué mi pensamiento de novato es erróneo?
Respuestas:
El patrón decorador es uno que favorece la composición sobre la herencia [otro paradigma de POO que es útil conocer]
El principal beneficio del patrón decorador: la subclasificación es permitir más opciones de mezcla y combinación. Si tiene, por ejemplo, 10 comportamientos diferentes que puede tener una ventana, entonces esto significa, con subclases, que necesita crear cada combinación diferente, que también inevitablemente incluirá una gran cantidad de reutilización de código.
Sin embargo, ¿qué sucede cuando decides agregar un nuevo comportamiento?
Con el decorador, solo agrega una nueva clase que describe este comportamiento, y eso es todo: el patrón le permite colocarlo de manera efectiva sin ninguna modificación en el resto del código.
Con subclases, tienes una pesadilla en tus manos.
Una pregunta que hizo fue "¿cómo la subclase cambia la clase principal?" No es que cambie la clase principal; cuando dice una instancia, significa cualquier objeto que haya 'instanciado' [si está utilizando Java o C #, por ejemplo, mediante el
new
comando]. A lo que se refiere es que, cuando agrega estos cambios a una clase, no tiene otra opción para que ese cambio esté allí, incluso si realmente no lo necesita.Alternativamente, puede poner toda su funcionalidad en una sola clase con activada / desactivada a través de indicadores ... pero esto termina con una sola clase que se hace más y más grande a medida que su proyecto crece.
No es inusual comenzar su proyecto de esta manera, y refactorizar en un patrón de decorador una vez que alcance una masa crítica efectiva.
Un punto interesante que debe hacerse: puede agregar la misma funcionalidad varias veces; por lo que podría, por ejemplo, tener una ventana con el doble, triple o cualquier cantidad o bordes que necesite.
El punto principal del patrón es habilitar los cambios en el tiempo de ejecución: es posible que no sepa cómo desea que se vea la ventana hasta que se ejecute el programa, y esto le permite modificarla fácilmente. Por supuesto, esto se puede hacer a través de la subclase, pero no tan bien.
Y, por último, permite agregar funcionalidad a las clases que quizás no pueda editar, por ejemplo, en clases selladas / finales, o las que se proporcionan desde otras API
fuente
Considere las posibilidades de agregar barras de desplazamiento y bordes con subclases. Si quieres todas las posibilidades, obtienes cuatro clases (Python):
Ahora, en
WindowWithScrollBarAndBorder.draw()
, la ventana se dibuja dos veces, y la segunda vez puede o no sobrescribir la barra de desplazamiento ya dibujada, dependiendo de la implementación. Por lo tanto, su código derivado está estrechamente vinculado a la implementación de otra clase, y debe preocuparse por eso cada vez que modifique elWindow
comportamiento de la clase. Una solución sería copiar y pegar el código de las superclases a las clases derivadas y ajustarlo a las necesidades de las clases derivadas, pero cada cambio en una superclase debe volver a pegarse y ajustarse nuevamente, por lo que nuevamente las clases derivadas son estrechamente acoplado a la clase base (a través de la necesidad de copiar-pegar-ajustar). Otro problema es que si necesita otra propiedad que una ventana puede tener o no, debe duplicar cada clase:Eso significa para un conjunto de características mutuamente independientes f con | f | siendo la cantidad de características, debe definir 2 ** | f | clases, por ejemplo. Si tiene 10 características, obtendrá 1024 clases estrechamente ajustadas. Si usa el Patrón de decorador, cada característica tiene su propia clase independiente y poco acoplada y solo tiene 1 + | f | clases (eso es 11 para el ejemplo anterior).
fuente
No soy un experto en este patrón en particular, pero tal como lo veo, el patrón Decorador se puede aplicar a clases que es posible que no tenga la capacidad de modificar o subclasificar (puede que no sean su código y estén selladas, por ejemplo ) En su ejemplo, ¿qué pasa si no escribió la clase Window pero la está consumiendo? Siempre que la clase Window tenga una interfaz y usted programe contra esa interfaz, su Decorador puede usar la misma interfaz pero extender la funcionalidad.
El ejemplo que mencionas en realidad está cubierto aquí bastante claramente:
http://www.oodesign.com/decorator-pattern.html
fuente