Pregunta

Estaba mirando el patrón Proxy y me parece muchísimo a los patrones Decorador, Adaptador y Puente.¿Estoy entendiendo mal algo?¿Cual es la diferencia?¿Por qué debería utilizar el patrón Proxy frente a los demás?¿Cómo los ha utilizado en el pasado en proyectos del mundo real?

¿Fue útil?

Solución

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

  • Proxy se puede usar cuando desea crear una instancia diferida 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 " 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 usa cuando tiene una interfaz abstracta y desea asignar esa interfaz a otro objeto que tenga una función funcional similar, pero una interfaz diferente.

  • Bridge 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.

  • Fachada es una interfaz de nivel superior (léase: más simple) para 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 a la colección de objetos. Ejemplo: un modelo de dominio para una sección de escuela, con métodos como countStudents(), reportAttendance(), assignSubstituteTeacher(), etc.

Otros consejos

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

También lo 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 contienen. Pero el adaptador deriva de una interfaz existente, mientras que la fachada crea una nueva interfaz.

  • Puente y 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á.

Mi opinión sobre el tema.

Los cuatro patrones tienen mucho en común; a los cuatro a veces se les llama informalmente envoltorios o patrones de envoltorio.Todos usan composición, envuelven el tema y delegan la ejecución al tema en algún momento, asignan una llamada a un 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 con prudencia, ahorran memoria y procesador.

Al promover el acoplamiento flexible, hacen que el código que alguna vez fue estable esté menos expuesto a cambios inevitables y sea más legible para los demás desarrolladores.

Adaptador

El adaptador adapta al sujeto (adaptado) a una interfaz diferente.De esta manera podemos agregar objetos y colocarlos en una colección de tipos nominalmente diferentes.

El adaptador expone solo los métodos relevantes al cliente, puede restringir todos los demás, revelando intenciones de uso para contextos particulares, como adaptar una 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 que salva vidas cuando se trata de equipos offshore ;-)

El propósito menos mencionado es evitar que la clase de materia tenga un exceso de 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 bajo un mismo sobre dando la impresión de herencia múltiple.

En cuanto al código, el adaptador es "delgado".No debería agregar mucho código a la clase adaptada, además de simplemente llamar al método adaptado y las conversiones de datos ocasionales necesarias para realizar dichas 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

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

Los decoradores suelen agregar (de forma transparente) funcionalidades al objeto envuelto, como registro, cifrado, formato o 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 utilizar de forma transparente en lugar de sus sujetos.Consulte BufferedOutputStream, sigue siendo OutputStream y puede usarse como tal.Esa es una diferencia técnica importante con respecto a los adaptadores.

Ejemplos de libros de texto de toda la familia de decoradores se encuentran fácilmente en JDK: Java IO.Todas las clases como Flujo de salida almacenado en búfer, Filtrar flujo de salida y flujo de salida de objetos son decoradores de Flujo de salida.Pueden tener capas de cebolla, donde un decorador se vuelve a decorar, agregando más funcionalidad.

Apoderado

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

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

  • Proxy remoto: el sujeto está en un servidor remoto, en una JVM diferente o incluso en una máquina que no está en el servidor remoto. Sistema 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 los Tecnología.

  • Proxy de carga perezosa: 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).La fachada 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 objeto complejo, simplificando el acceso a una estructura compleja.

La fachada envuelve una estructura compleja, proporcionándole una interfaz plana.Esto evita que el objeto del cliente quede expuesto 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 varía la implementación sino también la abstracción.Añade una indirecta 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 patrón de envoltura, así que aplíquelo con cuidado.

Diferencias en constructores.

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

  • Apoderado no está envolviendo un objeto existente.No hay ningún sujeto en el constructor.

  • Decorador y Adaptador envuelve un objeto ya existente, y eso suele ser así
    proporcionado en el constructor.

  • Fachada El constructor 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 – Adaptador de clasificación JAXB.El propósito de este adaptador es mapear una clase plana simple a una estructura más compleja requerida externamente y evitar una clase temática "contaminante" con anotaciones excesivas.

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!

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

decoraré puntos clave.

Decorator:

  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.

p. (con encadenamiento): java.io clases de paquetes relacionados con InputStream & amp; OutputStream interfaces

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

Proxy:

  1. Úselo para la inicialización diferida, la mejora del rendimiento al almacenar en caché el objeto y controlar 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: java.rmi clases de paquetes.

Adaptador :

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

p. java.io.InputStreamReader (Reader devuelve un java.util)

Bridge:

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

p. Clases de colección en List. ArrayList implementado por <=>.

Notas clave:

  1. Adaptador proporciona una interfaz diferente a su tema. Proxy proporciona la misma interfaz. Decorator proporciona una interfaz mejorada.
  2. Adapter cambia la interfaz de un objeto, Decorator mejora las responsabilidades de un objeto.
  3. Decorator y Proxy tienen diferentes propósitos pero estructuras similares
  4. Adapter hace que las cosas funcionen después de su diseño; Bridge los hace funcionar antes que ellos.
  5. Bridge está diseñado por adelantado para permitir que la abstracción y la implementación varíen independientemente. Adaptador se actualiza para que las clases no relacionadas funcionen juntas
  6. Decorator está diseñado para permitirle agregar responsabilidades a los objetos sin subclasificar.

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 de decoración?

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

Diferencias entre proxy y patrón de decorador

Son bastante similares, y las líneas entre ellos son bastante grises. Le sugiero que lea el Patrón de proxy y Patrón de decorador entradas en el 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.

Esta es una cita de Patrones de diseño de Head First

Las definiciones pertenecen al libro. Los ejemplos me pertenecen.

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

Adaptador : convierte una interfaz en 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. Dado 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, reúne todas esas referencias de interfaz bajo 1 paraguas y deja que decida / delegue para que sea simple.

Head First: " 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 & # 8217; es simplificar, mientras un adaptador & # 8217; s es convertir la interfaz a algo diferente. "

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:

  • Proxy encapsula el acceso de exterior a interior.
  • Decorador modifica o extiende el comportamiento del interior con el exterior.
  • Adaptador convierte la interfaz de interna a externa.
  • Bridge separa parte invariable del comportamiento (exterior) de la parte variable o dependiente de la plataforma (interior).

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

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

Lo uso con bastante frecuencia cuando consumo servicios web. El patrón de proxy probablemente debería cambiarse de nombre a algo más pragmático, como 'Wrapper Pattern & Quot ;. 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 los detalles de fondo, como qué versión está instalada (si la hay).

Hablando de 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 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 lenta. 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.

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)

  

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

     
      
  • Proxy se puede usar cuando desea instanciar un objeto de forma diferida, o   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 costoso 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 " Smart Proxy. " Esto se usa cuando quieres   agregar funcionalidad a un objeto, pero no extendiendo ese objeto   tipo. Esto le permite hacerlo en tiempo de ejecución.
  •   

DecoratorClass debería (podría) implementar la interfaz extendida de ObjectClass. Entonces ObjectClass podría ser reemplazado por DecoratorClass, pero no viceversa.

Ejemplo: agregar funcionalidad de adición

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 utiliza cuando tiene una interfaz abstracta y desea   asignar esa interfaz a otro objeto que tiene funcional similar   rol, pero una interfaz diferente.
  •   

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.

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

  •   
  • Fachada es una interfaz de nivel superior (léase: más simple) para un subsistema de   Una o más clases. Supongamos que tiene un concepto complejo que requiere   Múltiples objetos para representar. Hacer cambios a ese conjunto de objetos   es confuso, porque no siempre sabes 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 hacer   a la colección de objetos. Ejemplo: un modelo de dominio para una escuela   sección, con métodos como countStudents(), reportAttendance(),   assignSubstituteTeacher(), y así sucesivamente.

  •   

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

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

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);
                }

            }
        }
    }

}

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top