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 LoggingDBAuthorization
e 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 Proxy
con 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 Decorator
no 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 Decorator
como 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.