Diferencias entre Proxy y Patrón Decorador

136

¿Puedes dar una buena explicación de cuál es la diferencia entre Proxy y Decorator ?

La principal diferencia que veo es que cuando asumimos que Proxy usa composición y Decorator usa agregación, entonces parece claro que al usar múltiples (uno o más) Decoradores puedes modificar / agregar funcionalidades a instancias preexistentes (decorar), mientras que Proxy tiene su propia instancia interna de clase proxied y delega en ella agregando algunas características adicionales (comportamiento de proxy).

La pregunta es: ¿el Proxy creado con agregación sigue siendo Proxy o más bien Decorador ? ¿Está permitido (por definición en los patrones GoF) crear Proxy con agregación?

Łukasz Rzeszotarski
fuente
2
Algunos enlaces: Proxy y decorador
Sotirios Delimanolis
55
¿De dónde sacaste la idea de que Proxy usa composición y Decorator usa agregación?
CPerkins
1
@CPerkins ve mi comentario para la respuesta de Rahul Tripathi.
Łukasz Rzeszotarski
1
Y también decorador ( patterns.cs.up.ac.za/examples/ch2/decorator-theory.cs ) - obviamente agregación, proxy ( patterns.cs.up.ac.za/examples/ch2/proxy-theory.cs ) - Obviamente composición.
hyankov

Respuestas:

16

Aquí está la cita directa del GoF (página 216).

Aunque los decoradores pueden tener implementaciones similares a los servidores proxy, los decoradores tienen un propósito diferente. Un decorador agrega una o más responsabilidades a un objeto, mientras que un proxy controla el acceso a un objeto.

Los poderes varían en el grado en que se implementan como un decorador. Un proxy de protección podría implementarse exactamente como un decorador. Por otro lado, un proxy remoto no contendrá una referencia directa a su tema real sino solo una referencia indirecta, como "ID de host y dirección local en el host". Un proxy virtual comenzará con una referencia indirecta, como un nombre de archivo, pero eventualmente obtendrá y usará una referencia directa.

Las respuestas populares indican que un Proxy conoce el tipo concreto de su delegado. De esta cita podemos ver que no siempre es cierto.

La diferencia entre Proxy y Decorator según GoF es que Proxy restringe al cliente. Decorador no. Proxy puede restringir lo que un cliente hace mediante el control de acceso a la funcionalidad; o puede restringir lo que un cliente sabe al realizar acciones que son invisibles y desconocidas para el cliente. Decorator hace lo contrario: mejora lo que hace su delegado de manera visible para los clientes.

Podríamos decir que Proxy es una caja negra, mientras que Decorator es una caja blanca.

La relación de composición entre el contenedor y el delegado es la relación incorrecta en la que se debe enfocar al contrastar Proxy con Decorator, porque la composición es la característica que estos dos patrones tienen en común. La relación entre el contenedor y el cliente es lo que diferencia estos dos patrones.

  • Decorador informa y faculta a su cliente.
  • El proxy restringe y da poder a su cliente.
jaco0646
fuente
113

La verdadera diferencia no es la propiedad (composición versus agregación), sino más bien la información de tipo.

Un decorador está siempre pasó su delegado. Un Proxy podría crearlo él mismo, o podría tenerlo inyectado.

Pero un Proxy siempre conoce el tipo (más) específico del delegado. En otras palabras, el Proxy y su delegado tendrán el mismo tipo base, pero el Proxy apunta a algún tipo derivado. Un decorador apunta a su propio tipo base. Por lo tanto, la diferencia está en la información en tiempo de compilación sobre el tipo de delegado.

En un lenguaje dinámico, si el delegado se inyecta y tiene la misma interfaz, entonces no hay diferencia.

La respuesta a tu pregunta es sí".

cdunn2001
fuente
2
"Pero un Proxy siempre conoce el tipo (más) específico del delegado". No creo que sea cierto. Imagine proxy remoto. El mecanismo de representación no necesita conocer ningún detalle del objeto remoto. El sistema remoto registra el objeto con la interfaz especificada. Y el proxy local expone la misma interfaz.
Alexey
3
Tomé una clase sobre esto en Amazon de un profesor visitante que sabía lo que hacía. Existe una diferencia entre el uso de un ejecutable "proxy" (por ejemplo, con un servicio web) y el Patrón de diseño de proxy. Los UML del patrón Proxy y del patrón Decorator pueden ser diferentes. Pero nada impide que un Proxy tenga la misma API que su delegado. Decorator es un subconjunto estricto de Proxy, pero un Decorator aún puede llamarse Proxy dependiendo de si la API subyacente está garantizada a ser el mismo.
cdunn2001
85

Decorator Pattern se enfoca en agregar dinámicamente funciones a un objeto, mientras que Proxy Pattern se enfoca en controlar el acceso a un objeto.

EDITAR:-

Relación entre un Proxy y el sujeto real generalmente se establece en tiempo de compilación, Proxy lo instancia de alguna manera, mientras que Decorator se asigna al sujeto en tiempo de ejecución, conociendo solo la interfaz del sujeto.

Rahul Tripathi
fuente
55
Sin embargo, todavía se puede usar un Proxy para agregar funcionalidad. Piense en los poderes de AOP.
Sotirios Delimanolis
55
Totalmente de acuerdo señor. Convertiría eso, en otras palabras, lo que quise decir con Proxy Pattern, la clase proxy puede ocultar la información detallada de un objeto de su cliente. Por lo tanto, cuando usamos el Patrón de proxy, generalmente creamos una instancia de abject dentro de la clase de proxy. Y cuando se usa el Patrón Decorador, generalmente pasamos el objeto original como parámetro al constructor del decorador.
Rahul Tripathi
En este caso, cuando la instancia está 'oculta' en el proxy, la diferencia es clara para mí (como escribí), sin embargo, creo que a menudo las personas llaman como clases proxy que toman el objeto proxy que se pasó como parámetro del constructor. En este caso, la diferencia de agregar nueva funcionalidad o control es (muy) delgada para mí.
Łukasz Rzeszotarski
55
La relación entre un Proxy y el sujeto real generalmente se establece en tiempo de compilación, Proxy lo instancia de alguna manera, mientras que Decorator o Adapter se asignan al sujeto en tiempo de ejecución, conociendo solo la interfaz del sujeto. Espero que tenga sentido !!! :)
Rahul Tripathi
1
De lo contrario, podría agregar esta línea a su respuesta.
Łukasz Rzeszotarski
49

El decorador obtiene referencia para el objeto decorado (generalmente a través del constructor) mientras Proxy responsable de hacerlo solo.

El proxy no puede crear instancias de objetos envolventes (de este modo, hacer ORM para evitar el acceso innecesario a la base de datos si no se utilizan campos / captadores de objetos) mientras Decorator siempre mantiene el enlace a la instancia envuelta real.

Apoderado generalmente utilizado por los marcos para agregar seguridad o almacenamiento en caché / reposo y construido por el marco (no por el desarrollador habitual en sí).

El decorador generalmente se usa para agregar un nuevo comportamiento a las clases antiguas o heredadas por el propio desarrollador en función de la interfaz en lugar de la clase real (por lo que funciona en una amplia gama de instancias de interfaz, Proxy está en torno a una clase concreta).

gavenkoa
fuente
22

Diferencias clave

  1. Proxy proporciona la misma interfaz. Decorator proporciona una interfaz mejorada.
  2. Decorador y Proxy tienen diferentes propósitos pero estructuras similares. Ambos describen cómo proporcionar un nivel de indirección a otro objeto, y las implementaciones mantienen una referencia al objeto al que envían las solicitudes.
  3. El decorador puede verse como un compuesto degenerado con un solo componente. Sin embargo, un Decorador agrega responsabilidades adicionales: no está destinado a la agregación de objetos.
  4. Decorador admite composición recursiva
  5. La clase Decorator declara una relación de composición con la interfaz LCD (Denominador de clase más baja), y este miembro de datos se inicializa en su constructor.
  6. Use Proxy para la inicialización diferida, la mejora del rendimiento al almacenar en caché el objeto y controlar el acceso al cliente / llamante

El artículo de Sourcemaking cita las similitudes y diferencias de manera excelente.

Preguntas / enlaces SE relacionados:

¿Cuándo usar el patrón decorador?

¿Cuál es la diferencia exacta entre los patrones de adaptador y proxy?

Ravindra babu
fuente
3

Proxy y Decorator difieren en propósito y dónde se enfocan en la implementación interna. Proxy es para usar un objeto remoto, de proceso cruzado o de red cruzada como si fuera un objeto local. Decorator es para agregar un nuevo comportamiento a la interfaz original.

Si bien ambos patrones son similares en estructura, la mayor parte de la complejidad de Proxy radica en garantizar una comunicación adecuada con el objeto fuente. Decorator, por otro lado, se enfoca en la implementación del comportamiento agregado.

James Lin
fuente
¿Qué estás diciendo que es diferente de las otras 4 respuestas que ya están aquí?
Stephen Rauch
No sé si está todo ahí. Sentí la necesidad de intervenir después de leer las respuestas anteriores.
James Lin
1

Tomó un tiempo descubrir esta respuesta y lo que realmente significa. Algunos ejemplos deberían dejarlo más claro.

Proxy primero:

public interface Authorization {
    String getToken();
} 

Y:

// goes to the DB and gets a token for example
public class DBAuthorization implements Authorization {
    @Override
    public String getToken() {
        return "DB-Token";
    }
}

Y hay una persona que llama de esto Authorization, una muy tonta:

class Caller {
    void authenticatedUserAction(Authorization authorization) {
        System.out.println("doing some action with : " + authorization.getToken());
    }
}

Nada inusual hasta ahora, ¿verdad? Obtenga un token de un determinado servicio, use ese token. Ahora viene un requisito más para la imagen, agregar registro: es decir, registrar el token cada vez. Es simple para este caso, solo crea un Proxy:

public class LoggingDBAuthorization implements Authorization {

    private final DBAuthorization dbAuthorization = new DBAuthorization();

    @Override
    public String getToken() {
        String token = dbAuthorization.getToken();
        System.out.println("Got token : " + token);
        return token;
    }
}

¿Cómo usaríamos eso?

public static void main(String[] args) {
    LoggingDBAuthorization loggingDBAuthorization = new LoggingDBAuthorization();

    Caller caller = new Caller();
    caller.authenticatedUserAction(loggingDBAuthorization);
}

Tenga en LoggingDBAuthorization cuenta que contiene una instancia de DBAuthorization. Ambos LoggingDBAuthorizatione DBAuthorization implementar Authorization .

  • Un proxy contendrá alguna implementación concreta ( DBAuthorization) de la interfaz base ( Authorization). En otras palabras, un Proxy sabe exactamente lo que se está representando.

Decorator:

Comienza casi igual que Proxycon una interfaz:

public interface JobSeeker {
    int interviewScore();
}

y una implementación del mismo:

class Newbie implements JobSeeker  {
    @Override
    public int interviewScore() {
        return 10;
    }
}

Y ahora queremos agregar un candidato más experimentado, que agrega su puntaje de entrevista más el de otro JobSeeker:

@RequiredArgsConstructor 
public class TwoYearsInTheIndustry implements JobSeeker {

    private final JobSeeker jobSeeker;

    @Override
    public int interviewScore() {
        return jobSeeker.interviewScore() + 20;
    } 
}

Observe cómo dije eso más el de otro JobSeeker , no Newbie . A Decoratorno sabe exactamente qué está decorando, solo conoce el contrato de esa instancia decorada (lo sabe JobSeeker). Tome nota aquí de que esto es diferente aProxy ; que, por el contrario, sabe exactamente lo que está decorando.

¿Podría preguntarse si realmente hay alguna diferencia entre los dos patrones de diseño en este caso? ¿Qué pasa si tratamos de escribir el Decoratorcomo a Proxy?

public class TwoYearsInTheIndustry implements JobSeeker {

    private final Newbie newbie = new Newbie();

    @Override
    public int interviewScore() {
        return newbie.interviewScore() + 20;
    }
}

Esta es definitivamente una opción y destaca cuán cerca están estos patrones; todavía están destinados a diferentes escenarios como se explica en las otras respuestas.

Eugene
fuente
1

Proxy proporciona la misma interfaz para el objeto envuelto, Decorator le proporciona una interfaz mejorada, y Proxy generalmente administra el ciclo de vida de su objeto de servicio por sí mismo, mientras que la composición de Decoradores siempre es controlada por el cliente.

Ali Bayat
fuente