pattern design-patterns decorator bridge proxy-pattern

design-patterns - adapter pattern



¿En qué se diferencian los patrones de proxy, decorador, adaptador y puente? (13)

Creo que el código dará ideas claras (para complementar las respuestas de otros también). Consulte a continuación, (Enfoque los tipos que una clase implementa y ajusta)

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TestConsole { class Program { static void Main(string[] args) { /* Proxy */ Console.WriteLine(Environment.NewLine); Console.WriteLine("PROXY"); Console.WriteLine(Environment.NewLine); //instead of creating here create using a factory method, the facory method will return the proxy IReal realProxy = new RealProxy(); Console.WriteLine("calling do work with the proxy object "); realProxy.DoWork(); Console.WriteLine(Environment.NewLine); Console.WriteLine("ADAPTER"); Console.WriteLine(Environment.NewLine); /*Adapter*/ IInHand objectIHave = new InHand(); Api myApi = new Api(); //myApi.SomeApi(objectIHave); /*I cant do this, use a adapter then */ IActual myAdaptedObject = new ActualAdapterForInHand(objectIHave); Console.WriteLine("calling api with my adapted obj"); myApi.SomeApi(myAdaptedObject); Console.WriteLine(Environment.NewLine); Console.WriteLine("DECORATOR"); Console.WriteLine(Environment.NewLine); /*Decorator*/ IReady maleReady = new Male(); Console.WriteLine("now male is going to get ready himself"); maleReady.GetReady(); Console.WriteLine(Environment.NewLine); IReady femaleReady = new Female(); Console.WriteLine("now female is going to get ready her self"); femaleReady.GetReady(); Console.WriteLine(Environment.NewLine); IReady maleReadyByBeautician = new Beautician(maleReady); Console.WriteLine("now male is going to get ready by beautician"); maleReadyByBeautician.GetReady(); Console.WriteLine(Environment.NewLine); IReady femaleReadyByBeautician = new Beautician(femaleReady); Console.WriteLine("now female is going to get ready by beautician"); femaleReadyByBeautician.GetReady(); Console.WriteLine(Environment.NewLine); Console.ReadLine(); } } /*Proxy*/ public interface IReal { void DoWork(); } public class Real : IReal { public void DoWork() { Console.WriteLine("real is doing work "); } } public class RealProxy : IReal { IReal real = new Real(); public void DoWork() { real.DoWork(); } } /*Adapter*/ public interface IActual { void DoWork(); } public class Api { public void SomeApi(IActual actual) { actual.DoWork(); } } public interface IInHand { void DoWorkDifferently(); } public class InHand : IInHand { public void DoWorkDifferently() { Console.WriteLine("doing work slightly different "); } } public class ActualAdapterForInHand : IActual { IInHand hand = null; public ActualAdapterForInHand() { hand = new InHand(); } public ActualAdapterForInHand(IInHand hnd) { hand = hnd; } public void DoWork() { hand.DoWorkDifferently(); } } /*Decorator*/ public interface IReady { void GetReady(); } public class Male : IReady { public void GetReady() { Console.WriteLine("Taking bath.. "); Console.WriteLine("Dress up...."); } } public class Female : IReady { public void GetReady() { Console.WriteLine("Taking bath.. "); Console.WriteLine("Dress up...."); Console.WriteLine("Make up...."); } } //this is a decorator public class Beautician : IReady { IReady ready = null; public Beautician(IReady rdy) { ready = rdy; } public void GetReady() { ready.GetReady(); Console.WriteLine("Style hair "); if (ready is Female) { for (int i = 1; i <= 10; i++) { Console.WriteLine("doing ready process " + i); } } } } }

Estaba mirando el patrón de proxy, y para mí, se parece mucho a los patrones de decorador, adaptador y puente. ¿Estoy malinterpretando algo? ¿Cual es la diferencia? ¿Por qué usaría el patrón Proxy contra los otros? ¿Cómo los has usado en el pasado en proyectos del mundo real?


El patrón de diseño no es matemático, es una combinación de arte e ingeniería de software. No hay nada como para este requisito, tiene que usar proxy, puente, etc. Los patrones de diseño se crean para resolver los problemas. Si anticipa un problema de diseño, entonces utilícelo. Con base en la experiencia, llegará a conocer un problema específico, qué patrón usar. Si usted es bueno en los principios de diseño sólido, habría implementado un patrón de diseño sin saber que es un patrón. Ejemplo común es patrones de fábricas y fábricas.

Por lo tanto, concéntrese más en los principios de diseño sólido, principios de codificación limpios y ttd


Esta es una cita de Head First Design Patterns

Las definiciones pertenecen al libro. Los ejemplos me pertenecen.

Decorador : no altera la interfaz, pero agrega responsabilidad. Suponga que tiene una interfaz de automóvil, cuando implemente esto para un modelo diferente del automóvil (s, sv, sl) es posible que deba agregar más responsabilidad para algunos modelos. Al igual que tiene techo solar, airbag etc.

Adaptador - Convierte una interfaz a otra. Tienes una interfaz de coche y te gustaría que actuara como un jeep. Así que tomas el coche, lo modificas y lo conviertes en un jeep. Ya que no es un jeep real. Pero actúa como un jeep.

Fachada - Facilita una interfaz. Supongamos que tiene interfaces de coche, avión, nave. En realidad, todo lo que necesita es una clase que envíe personas de un lugar a otro. Quieres que la fachada decida qué vehículo utilizar. Luego, recopila todas esas referencias de interfaz bajo 1 paraguas y deja que decida / delegue para que sea sencillo.

Head First: "Una fachada no solo simplifica una interfaz, también separa a un cliente de un subsistema de componentes. Las fachadas y los adaptadores pueden envolver varias clases, pero la intención de una fachada es simplificar, mientras que la de un adaptador es convertir la interfaz en algo diferente. "


Hablando de la implementación detallada, encuentro una diferencia entre Proxy y Decorator, Adapter, Facade ... En la implementación común de estos patrones, hay un objeto objetivo envuelto por un objeto envolvente. El cliente utiliza el objeto de encierro en lugar del objeto de destino. Y el objeto de destino en realidad juega un papel importante dentro de algunos de los métodos para encerrar objetos.

Sin embargo, en el caso de Proxy, el objeto adjunto puede reproducir algunos métodos por sí mismo, simplemente inicializa el objeto de destino cuando el cliente llama a algunos métodos en los que necesita que participe el objeto de destino. Esto es una inicialización perezosa. En el caso de otros patrones, el objeto envolvente se basa virtualmente en el objeto objetivo. Por lo tanto, el objeto de destino siempre se inicializa junto con el objeto de encierro en los constructores / definidores.

Otra cosa, un proxy hace exactamente lo que hace un objetivo, mientras que otros patrones agregan más funcionalidad al objetivo.


Hay una gran cantidad de superposición en muchos de los patrones de GoF. Todos están basados ​​en el poder del polimorfismo y, a veces, solo difieren en sus intenciones. (estrategia contra estado)

Mi comprensión de los patrones aumentó 100 veces después de leer los patrones de diseño de Head First .

¡Lo recomiendo altamente!


Lo uso bastante a menudo al consumir servicios web. El patrón de proxy probablemente debería cambiar su nombre a algo más pragmático, como "Patrón de envoltura". También tengo una biblioteca que es un Proxy para MS Excel. Es muy fácil automatizar Excel, sin tener que preocuparme por detalles de fondo como por ejemplo. La versión está instalada (si la hay).


Los cuatro patrones implican envolver el objeto / clase interno con el externo, por lo que son muy similares estructuralmente. Me gustaría delinear la diferencia por el propósito:

  • Proxy encapsula el acceso en el exterior al interior.
  • El decorador modifica o amplía el comportamiento de lo interno con lo externo.
  • Adaptador convierte la interfaz de interior a exterior.
  • El puente separa la parte invariable del comportamiento (exterior) de la parte variable o dependiente de la plataforma (interno).

Y por la variación de la interfaz entre los objetos internos y externos:

  • En las interfaces de proxy son las mismas.
  • En Decorator las interfaces son las mismas.
  • en Adaptador las interfaces son diferentes formalmente, pero cumplen el mismo propósito.
  • En Bridge las interfaces son conceptualmente diferentes.

Me gustaría agregar ejemplos a la respuesta de Bill Karwing (lo cual es genial, por cierto). También agrego algunas diferencias clave de implementación, que creo que faltan.

Las partes citadas son de la respuesta de [ https://.com/a/350471/1984346] (Bill Karwing)

Proxy, Decorator, Adapter y Bridge son variaciones de "envolver" una clase. Pero sus usos son diferentes.

  • Se puede usar un proxy cuando desee crear una instancia perezosa de un objeto u ocultar el hecho de que está llamando a un servicio remoto, o controlar el acceso al objeto.

ProxyClass y ObjectClass que son proxy, deben implementar la misma interfaz, por lo que son intercambiables

Ejemplo: objeto caro proxy

class ProxyHumanGenome implements GenomeInterface { private $humanGenome = NULL; // humanGenome class is not instantiated at construct time function __construct() { } function getGenomeCount() { if (NULL == $this->humanGenome) { $this->instantiateGenomeClass(); } return $this->humanGenome->getGenomeCount(); } } class HumanGenome implement GenomeInterface { ... }

  • Decorador también se llama "Proxy inteligente". Esto se usa cuando desea agregar funcionalidad a un objeto, pero no extendiendo el tipo de ese objeto. Esto le permite hacerlo en tiempo de ejecución.

DecoratorClass debería (podría) implementar una interfaz extendida de ObjectClass. Entonces, ObjectClass podría ser reemplazado por DecoratorClass, pero no al revés.

Ejemplo: agregar funcionalidad de suma

class DecoratorHumanGenome implements CheckGenomeInterface { // ... same code as previous example // added functionality public function isComplete() { $this->humanGenome->getCount >= 21000 } } interface CheckGenomeInterface extends GenomeInterface { public function isComplete(); } class HumanGenome implement GenomeInterface { ... }

  • El adaptador se usa cuando tiene una interfaz abstracta, y desea asignar esa interfaz a otro objeto que tiene un rol funcional similar, pero una interfaz diferente.

Diferencias de implementación Proxy, decorador, adaptador

Adaptador proporciona una interfaz diferente a su tema. Proxy proporciona la misma interfaz. Decorador proporciona una interfaz mejorada.

  • Bridge es muy similar a Adapter, pero lo llamamos Bridge cuando define la interfaz abstracta y la implementación subyacente. Es decir, no se está adaptando a algún código heredado o de terceros, usted es el diseñador de todo el código, pero necesita poder intercambiar diferentes implementaciones.

  • Facade es una interfaz de nivel superior (lectura: más simple) para un subsistema de una o más clases. Supongamos que tiene un concepto complejo que requiere la representación de múltiples objetos. Hacer cambios a ese conjunto de objetos es confuso, porque no siempre se sabe a qué objeto tiene el método que necesita llamar. Ese es el momento de escribir una fachada que proporciona métodos de alto nivel para todas las operaciones complejas que puede realizar en la colección de objetos. Ejemplo: un modelo de dominio para una sección escolar, con métodos como countStudents() , reportAttendance() , assignSubstituteTeacher() , etc.

La mayor parte de la información en esta respuesta proviene de https://sourcemaking.com/design_patterns , que recomiendo como un excelente recurso para los patrones de diseño.


Mi opinión sobre el tema.

Los cuatro patrones tienen mucho en común, los cuatro a veces se denominan envolturas informalmente o patrones de envoltura. Todos utilizan la composición, envuelven el tema y delegan la ejecución al tema en algún momento, hacen un mapeo de una llamada de método a otra. Le ahorran al cliente la necesidad de tener que construir un objeto diferente y copiar sobre todos los datos relevantes. Si se usan sabiamente, ahorran memoria y procesador.

Al promover el acoplamiento suelto, una vez que el código estable está menos expuesto a cambios inevitables y es más legible para los desarrolladores.

Adaptador

Adaptador adapta sujeto (adaptee) a una interfaz diferente. De esta manera podemos agregar objetos a una colección de tipos nominalmente diferentes.

El adaptador expone solo los métodos relevantes al cliente, puede restringir todos los demás, revelando las intenciones de uso para contextos particulares, como adaptar la biblioteca externa, hacer que parezca menos general y más centrado en las necesidades de nuestra aplicación. Los adaptadores aumentan la legibilidad y la autodescripción de nuestro código.

Los adaptadores protegen a un equipo del código volátil de otros equipos; una herramienta para salvar vidas cuando se trata de equipos offshore ;-)

El propósito menos mencionado es evitar que la clase del sujeto supere las anotaciones. Con tantos marcos basados ​​en anotaciones, este uso se vuelve más importante que nunca.

El adaptador ayuda a sortear la limitación de Java de una sola herencia. Puede combinar varios adaptados en un sobre dando impresión de herencia múltiple.

Código sabio, el adaptador es "delgado". No debe agregar mucho código a la clase adaptee, además de simplemente llamar al método adaptee y las conversiones de datos ocasionales necesarias para hacer tales llamadas.

No hay muchos buenos ejemplos de adaptadores en JDK o bibliotecas básicas. Los desarrolladores de aplicaciones crean adaptadores, para adaptar las bibliotecas a las interfaces específicas de la aplicación.

Decorador

Decorator no solo delega, no solo asigna un método a otro, sino que hace más, modifica el comportamiento de algunos métodos de sujeto, puede decidir no llamar método de sujeto en absoluto, delegar a un objeto diferente, un objeto auxiliar.

Por lo general, los decoradores agregan (de forma transparente) la funcionalidad al objeto envuelto, como el registro, el cifrado, el formato o la compresión del sujeto. Esta nueva funcionalidad puede traer un montón de código nuevo. Por lo tanto, los decoradores suelen ser mucho más "gruesos" que los adaptadores.

El decorador debe ser una subclase de la interfaz del sujeto. Se pueden utilizar de forma transparente en lugar de sus sujetos. Consulte BufferedOutputStream, todavía es OutputStream y se puede usar como tal. Esa es una gran diferencia técnica de los adaptadores.

Los ejemplos de libros de texto de toda la familia de decoradores se encuentran fácilmente en JDK: Java IO. Todas las clases como BufferedOutputStream , FilterOutputStream y ObjectOutputStream son decoradores de OutputStream . Pueden ser capas de cebolla, donde un decorador se decora nuevamente, agregando más funcionalidad.

Apoderado

Proxy no es un contenedor típico. Es posible que el objeto envuelto, el sujeto proxy, aún no exista en el momento de la creación del proxy. Proxy a menudo lo crea internamente. Puede ser un objeto pesado creado a pedido, o es un objeto remoto en una JVM diferente o en un nodo de red diferente e incluso un objeto no Java, un componente en el código nativo. No es necesario envolver o delegar en ningún otro objeto.

Los ejemplos más típicos son los proxies remotos, los inicializadores de objetos pesados ​​y los proxies de acceso.

  • Proxy remoto: el sujeto se encuentra en un servidor remoto, una JVM diferente o incluso un sistema no Java. El proxy traduce las llamadas de método a llamadas RMI / REST / SOAP o lo que sea necesario, protegiendo al cliente de la exposición a la tecnología subyacente.

  • Lazy Load Proxy: inicializa completamente el objeto solo el primer uso o el primer uso intensivo.

  • Proxy de acceso - control de acceso al tema.

Fachada

La fachada está estrechamente relacionada con el principio de diseño del conocimiento mínimo (Ley de Demeter). Facade es muy similar a Adapter. Ambos se envuelven, ambos mapean un objeto a otro, pero difieren en la intención. La fachada aplana la estructura compleja de un sujeto, el gráfico de objeto complejo, simplifica el acceso a una estructura compleja.

La fachada envuelve una estructura compleja, proporcionando una interfaz plana a la misma. Esto evita que el objeto del cliente se exponga a relaciones internas en la estructura del sujeto, por lo que promueve un acoplamiento suelto.

Puente

Variante más compleja del patrón Adaptador donde no solo varía la implementación sino también la abstracción. Añade un indirection más a la delegación. La delegación extra es el puente. Se desacopla Adaptador incluso de la interfaz de adaptación. Aumenta la complejidad más que cualquier otro de los otros patrones de envoltura, así que aplíquelo con cuidado.

Diferencias en constructores.

Las diferencias de patrones también son obvias cuando se mira a sus constructores.

  • El proxy no está envolviendo un objeto existente. No hay asignatura en constructor.

  • El decorador y el adaptador envuelven un objeto ya existente, y tal es típicamente
    Proporcionado en el constructor.

  • El constructor de fachadas toma el elemento raíz de un gráfico de objeto completo, de lo contrario se ve igual que el adaptador.

Ejemplo de la vida real - JAXB Marshalling Adapter . El propósito de este adaptador es el mapeo de una clase plana simple a una estructura más compleja que se requiere externamente y para evitar la clase de sujeto "contaminante" con anotaciones excesivas.


Proxy, Decorator, Adapter y Bridge son variaciones de "envolver" una clase. Pero sus usos son diferentes.

  • Se puede usar un proxy cuando desee crear una instancia perezosa de un objeto u ocultar el hecho de que está llamando a un servicio remoto, o controlar el acceso al objeto.

  • Decorador también se llama "Proxy inteligente". Esto se usa cuando desea agregar funcionalidad a un objeto, pero no extendiendo el tipo de ese objeto. Esto le permite hacerlo en tiempo de ejecución.

  • El adaptador se usa cuando tiene una interfaz abstracta, y desea asignar esa interfaz a otro objeto que tiene un rol funcional similar, pero una interfaz diferente.

  • Bridge es muy similar a Adapter, pero lo llamamos Bridge cuando define la interfaz abstracta y la implementación subyacente. Es decir, no se está adaptando a algún código heredado o de terceros, usted es el diseñador de todo el código, pero necesita poder intercambiar diferentes implementaciones.

  • Facade es una interfaz de nivel superior (lectura: más simple) para un subsistema de una o más clases. Supongamos que tiene un concepto complejo que requiere la representación de múltiples objetos. Hacer cambios a ese conjunto de objetos es confuso, porque no siempre se sabe a qué objeto tiene el método que necesita llamar. Ese es el momento de escribir una fachada que proporciona métodos de alto nivel para todas las operaciones complejas que puede realizar en la colección de objetos. Ejemplo: un modelo de dominio para una sección escolar, con métodos como countStudents() , reportAttendance() , assignSubstituteTeacher() , etc.


Son bastante similares, y las líneas entre ellos son bastante grises. Le sugiero que lea las entradas Proxy Pattern y Decorator Pattern en el wiki de c2.

Las entradas y discusiones allí son bastante extensas, y también enlazan a otros artículos relevantes. Por cierto, el wiki de c2 es excelente cuando se pregunta sobre los matices entre diferentes patrones.

Para resumir las entradas de c2, diría que un decorador agrega / modifica el comportamiento, pero un proxy tiene más que ver con el control de acceso (ejemplificación perezosa, acceso remoto, seguridad, etc.). Pero como dije, las líneas entre ellos son grises, y veo referencias a proxies que fácilmente podrían verse como decoradores y viceversa.


Todas las buenas respuestas de los expertos ya han explicado qué significa cada patrón.

Decoraré los puntos clave.

Decorador:

  1. Agregar comportamiento al objeto en tiempo de ejecución . La herencia es la clave para lograr esta funcionalidad, que es tanto una ventaja como una desventaja de este patrón.
  2. Modifica el comportamiento de la interfaz.

por ejemplo (con encadenamiento): clases de paquete java.io relacionadas con las interfaces InputStream y OutputStream

FileOutputStream fos1 = new FileOutputStream("data1.txt"); ObjectOutputStream out1 = new ObjectOutputStream(fos1);

Apoderado:

  1. Úselo para la inicialización lenta, la mejora del rendimiento almacenando en caché el objeto y controlando el acceso al cliente / llamante . Puede proporcionar un comportamiento alternativo o llamar a un objeto real. Durante este proceso, puede crear un nuevo objeto.
  2. A diferencia de Decorator , que permite el encadenamiento de objetos, Proxy no permite el encadenamiento.

Por ejemplo: clases de paquete java.rmi .

Adaptador:

  1. Permite que dos interfaces no relacionadas trabajen juntas a través de los diferentes objetos , posiblemente desempeñando el mismo rol.
  2. Modifica la interfaz original .

por ejemplo, java.io.InputStreamReader ( InputStream devuelve un Reader )

Puente:

  1. Permite que tanto las abstracciones como las implementaciones varíen independientemente .
  2. Utiliza la composición sobre la herencia .

Por ejemplo, clases de colección en java.util . List implementada por ArrayList .

Notas clave:

  1. Adaptador proporciona una interfaz diferente a su tema. Proxy proporciona la misma interfaz. Decorador proporciona una interfaz mejorada.
  2. El adaptador cambia la interfaz de un objeto, Decorator mejora las responsabilidades de un objeto.
  3. Decorador y Proxy tienen diferentes propósitos pero estructuras similares.
  4. El adaptador hace que las cosas funcionen una vez que están diseñadas; Puente les hace trabajar antes de que sean.
  5. Bridge está diseñado por adelantado para permitir que la abstracción y la implementación varíen independientemente. Se adapta el adaptador para que las clases no relacionadas trabajen juntas
  6. Decorator está diseñado para permitirle agregar responsabilidades a los objetos sin crear subclases.

Eche un vistazo a las preguntas / artículos de SE sobre ejemplos de varios patrones de diseño.

¿Cuándo usar el patrón decorador?

¿Cuándo usas el patrón de puente? ¿En qué se diferencia del patrón adaptador?

Diferencias entre Proxy y Decorator Pattern


Como dice la respuesta de Bill, sus casos de uso son diferentes .

Así son sus estructuras.

  • Proxy y Decorator tienen la misma interfaz que sus tipos envueltos, pero el proxy crea una instancia bajo el capó, mientras que el decorador toma una instancia en el constructor.

  • Tanto el adaptador como la fachada tienen una interfaz diferente de la que envuelven. Pero el adaptador deriva de una interfaz existente, mientras que la fachada crea una nueva interfaz.

  • El puente y el adaptador apuntan a un tipo existente. Pero el puente apuntará a un tipo abstracto, y el adaptador podría apuntar a un tipo concreto. El puente le permitirá vincular la implementación en tiempo de ejecución, mientras que el adaptador generalmente no lo hará.