Estaba mirando el Patrón Proxy, y para mí parece mucho como los patrones Decorador, Adaptador y Puente. ¿Estoy malinterpretando algo? ¿Cual es la diferencia? ¿Por qué usaría el patrón Proxy en comparación con los demás? ¿Cómo los has usado en el pasado en proyectos del mundo real?
design-patterns
decorator
bridge
proxy-pattern
Charles Graham
fuente
fuente
Respuestas:
Proxy, Decorator, Adapter y Bridge son todas variaciones en "envolver" una clase. Pero sus usos son diferentes.
El proxy se puede usar cuando desea instanciar un objeto de forma diferida, ocultar el hecho de que está llamando a un servicio remoto o controlar el acceso al objeto.
Decorator también se llama "Smart Proxy". 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 utiliza cuando tiene una interfaz abstracta y desea asignar esa interfaz a otro objeto que tenga una función funcional similar, pero una interfaz diferente.
Puente es muy similar a Adapter, pero lo llamamos Bridge cuando define tanto la interfaz abstracta como la implementación subyacente. Es decir, no se está adaptando a algún código heredado o de terceros, es el diseñador de todo el código pero necesita poder intercambiar diferentes implementaciones.
Facade es una interfaz de nivel superior (léase: más simple) a un subsistema de una o más clases. Suponga que tiene un concepto complejo que requiere múltiples objetos para representar. Hacer cambios en ese conjunto de objetos es confuso, porque no siempre sabes qué objeto tiene el método al que debes llamar. Es el momento de escribir una Fachada que proporcione 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 de la escuela, con métodos como
countStudents()
,reportAttendance()
,assignSubstituteTeacher()
, y así sucesivamente.fuente
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.
Adaptador y 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á emparejar la implementación en tiempo de ejecución, mientras que el adaptador generalmente no lo hará.
fuente
Mi opinión sobre el tema.
Los cuatro patrones tienen mucho en común, los cuatro a veces se denominan informalmente envoltorios o patrones de envoltorio. Todos usan la composición, ajustan el tema y delegan la ejecución al tema en algún momento, mapean una llamada de método a otra. Le ahorran al cliente la necesidad de tener que construir un objeto diferente y copiar todos los datos relevantes. Si se usan sabiamente, ahorran memoria y procesador.
Al promover un acoplamiento flexible, hacen que el código una vez estable esté menos expuesto a cambios inevitables y sea mejor legible para otros desarrolladores.
Adaptador
El adaptador adapta el sujeto (adaptado) 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 intentos 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 de salvamento cuando se trata de equipos offshore ;-)
El propósito menos mencionado es evitar que la clase de asignaturas exceda las anotaciones. Con tantos marcos basados en anotaciones, este uso se vuelve más importante que nunca.
El adaptador ayuda a evitar la limitación de Java de una sola herencia. Puede combinar varios adaptadores en un sobre dando la 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 realizar tales llamadas.
No hay muchos buenos ejemplos de adaptadores en JDK o bibliotecas básicas. Los desarrolladores de aplicaciones crean adaptadores para adaptar bibliotecas a interfaces específicas de aplicaciones.
Decorador
Decorator no solo delega, no solo asigna un método a otro, hacen más, modifican el comportamiento de algunos métodos de sujeto, puede decidir no llamar al método de sujeto en absoluto, delegar a un objeto diferente, un objeto auxiliar.
Los decoradores suelen agregar funcionalidad (transparente) al objeto envuelto, como el registro, el cifrado, el formateo o la compresión del sujeto. Esta nueva funcionalidad puede traer mucho código nuevo. Por lo tanto, los decoradores suelen ser mucho más "gordos" que los adaptadores.
El decorador debe ser una subclase de la interfaz del sujeto. Se pueden usar de forma transparente en lugar de sus sujetos. Vea BufferedOutputStream, todavía es OutputStream y puede usarse 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
El 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 un nodo de red diferente e incluso un objeto no Java, un componente en el código nativo. No tiene que envolver o delegar necesariamente a otro objeto en absoluto.
Los ejemplos más típicos son proxies remotos, inicializadores de objetos pesados y proxies de acceso.
Proxy remoto: el sujeto está en un servidor remoto, una JVM diferente o incluso un sistema que no es Java. Proxy traduce 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.
Proxy de carga diferida: inicialice completamente el objeto solo el primer uso o el primer uso intensivo.
Proxy de acceso: controla el acceso al sujeto.
Fachada
La fachada está estrechamente asociada con el Principio de diseño del conocimiento mínimo (Ley de Demeter). Facade es muy similar al adaptador. Ambos se envuelven, ambos asignan un objeto a otro, pero difieren en la intención. Fachada aplana la estructura compleja de un sujeto, gráfico de objetos complejos, simplificando el acceso a una estructura compleja.
Fachada envuelve una estructura compleja, proporcionándole una interfaz plana. Esto evita que el objeto del cliente se exponga a relaciones internas en la estructura del sujeto, promoviendo así un acoplamiento flojo.
Puente
Variante más compleja del patrón Adaptador donde no solo la implementación varía sino también la abstracción. Agrega una indirección más a la delegación. La delegación extra es el puente. Desacopla el adaptador incluso de la interfaz de adaptación. Aumenta la complejidad más que cualquier otro de los otros patrones de envoltura, así que aplique con cuidado.
Diferencias en constructores
Las diferencias de patrones también son obvias cuando se observan sus constructores.
Proxy no está envolviendo un objeto existente. No hay asignatura en constructor.
Decorator and Adapter sí envuelve el objeto ya existente, y normalmente se
proporciona 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 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 requerida externamente y para evitar la clase de sujeto "contaminante" con anotaciones excesivas.
fuente
Hay una gran superposición en muchos de los patrones de GoF. Todos están construidos sobre el poder del polimorfismo y, a veces, solo difieren en su intención. (estrategia versus estado)
Mi comprensión de los patrones aumentó 100 veces después de leer Head First Design Patterns .
¡Lo recomiendo altamente!
fuente
Todas las buenas respuestas de los expertos ya han explicado qué significa cada patrón.
Voy a decorar los puntos clave.
Decorador:
por ejemplo (con encadenamiento):
java.io
clases de paquetes relacionados conInputStream
&OutputStream
interfacesApoderado:
Por ejemplo:
java.rmi
clases de paquetes.Adaptador:
por ejemplo
java.io.InputStreamReader
(InputStream
devuelve aReader
)Puente:
por ejemplo, clases de colección en
java.util
.List
implementado porArrayList
.Notas clave:
Eche un vistazo a excelentes preguntas / artículos de SE con respecto a ejemplos de varios patrones de diseño
¿Cuándo usar el patrón decorador?
¿Cuándo usas el patrón de puente? ¿Cómo es diferente del patrón del adaptador?
Diferencias entre Proxy y Patrón Decorador
fuente
Son bastante similares, y las líneas entre ellos son bastante grises. Te sugiero que leas el entradas de Patrón de proxy y Patrón de decorador en la wiki de c2.
Las entradas y discusiones allí son bastante extensas, y también enlazan con otros artículos relevantes. Por cierto, el wiki de c2 es excelente cuando te preguntas sobre los matices entre los diferentes patrones.
Para resumir las entradas de c2, diría que un decorador agrega / cambia el comportamiento, pero un proxy tiene más que ver con el control de acceso (instanciación diferida, acceso remoto, seguridad, etc.). Pero como dije, las líneas entre ellos son grises, y veo referencias a proxies que podrían verse fácilmente como decoradores y viceversa.
fuente
Los cuatro patrones implican envolver el objeto / clase interno con el externo, por lo que son muy similares estructuralmente. Describiría la diferencia por el propósito:
Y por variación de interfaz entre objetos internos y externos:
fuente
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 diferentes modelos 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. Tiene una interfaz de automóvil y le gustaría que actúe como un jeep. Entonces tomas el auto, lo modificas y te conviertes en un jeep. Ya que no es un verdadero jeep. Pero actúa como un jeep.
Fachada : simplifica la interfaz. Suponga que tiene interfaces para automóviles, aviones y barcos. En realidad, todo lo que necesitas es una clase que envíe personas de un lugar a otro. Desea que la fachada decida qué vehículo usar. Luego recopila todas esas referencias de interfaz bajo 1 paraguas y deja que decida / delegue para que sea simple.
Primero: "Una fachada no solo simplifica una interfaz, sino que desacopla 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 un adaptador es convertir la interfaz en algo diferente. "
fuente
Lo uso con bastante frecuencia cuando consumo servicios web. El Proxy Pattern probablemente debería renombrarse a algo más pragmático, como 'Wrapper Pattern ". También tengo una biblioteca que es un Proxy para MS Excel. Hace que sea muy fácil automatizar Excel, sin tener que preocuparse por detalles de fondo como La versión está instalada (si la hay).
fuente
Hablando de implementación detallada, encuentro una diferencia entre Proxy y Decorador, Adaptador, Fachada ... En la implementación común de estos patrones hay un objeto objetivo envuelto por un objeto envolvente. El cliente utiliza el objeto adjunto en lugar del objeto de destino. Y el objeto de destino realmente juega un papel importante dentro de algunos de los métodos de encerrar el objeto.
Sin embargo, en el caso de Proxy, el objeto que encierra puede reproducir algunos métodos por sí mismo, solo inicializa el objeto de destino cuando el cliente llama a algunos métodos en los que necesita que participe el objeto de destino. Esta es una inicialización diferida. 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 delimitador en constructores / establecedores.
Otra cosa, un proxy hace exactamente lo que hace un objetivo, mientras que otros patrones agregan más funcionalidad al objetivo.
fuente
Me gustaría agregar ejemplos a la respuesta de Bill Karwing (lo cual es genial por cierto). Agrego también algunas diferencias clave de implementación, que siento que faltan
Las partes citadas son de la respuesta de [ https://stackoverflow.com/a/350471/1984346] (Bill Karwing)
ProxyClass y ObjectClass que son proxy, deben implementar la misma interfaz, por lo que son intercambiables
Ejemplo: objeto costoso proxy
DecoratorClass debería (podría) implementar la interfaz extendida de ObjectClass. Entonces ObjectClass podría ser reemplazado por DecoratorClass, pero no al revés.
Ejemplo: agregar funcionalidad adicional
Diferencias de implementación Proxy, Decorador, Adaptador
El adaptador proporciona una interfaz diferente a su tema. Proxy proporciona la misma interfaz. Decorator proporciona una interfaz mejorada.
La mayor parte de la información en esta respuesta proviene de https://sourcemaking.com/design_patterns , que recomiendo como un excelente recurso para patrones de diseño.
fuente
Creo que el código dará ideas claras (para complementar las respuestas de otros también). Vea a continuación, (Enfoque los tipos que una clase implementa y ajusta)
fuente
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 que tiene que usar proxy, puente, etc. Se crean patrones de diseño para resolver los problemas. Si anticipa un problema de diseño, úselo. Según la experiencia, conocerá el problema específico, qué patrón utilizar. Si eres bueno en principios de diseño sólidos, habrías implementado un patrón de diseño sin saber que es un patrón. Un ejemplo común son los patrones de fábrica y de fábrica.
Por lo tanto, concéntrese más en principios sólidos de diseño, principios de codificación limpios y ttd
fuente