Ci è voluto un po 'per capire questa risposta e cosa significa veramente. Alcuni esempi dovrebbero renderlo più chiaro.
Proxy
primo:
public interface Authorization {
String getToken();
}
E :
// goes to the DB and gets a token for example
public class DBAuthorization implements Authorization {
@Override
public String getToken() {
return "DB-Token";
}
}
E c'è un chiamante di questo Authorization
, piuttosto stupido:
class Caller {
void authenticatedUserAction(Authorization authorization) {
System.out.println("doing some action with : " + authorization.getToken());
}
}
Niente di insolito finora, giusto? Ottieni un token da un determinato servizio, usa quel token. Ora arriva un ulteriore requisito all'immagine, aggiungi la registrazione: significa che registri il token ogni volta. È semplice per questo caso, basta creare 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;
}
}
Come lo useremmo?
public static void main(String[] args) {
LoggingDBAuthorization loggingDBAuthorization = new LoggingDBAuthorization();
Caller caller = new Caller();
caller.authenticatedUserAction(loggingDBAuthorization);
}
Si noti che LoggingDBAuthorization
contiene un'istanza di DBAuthorization
. Entrambi LoggingDBAuthorization
e DBAuthorization
attuare Authorization
.
- Un proxy conterrà alcune implementazioni concrete (
DBAuthorization
) dell'interfaccia di base ( Authorization
). In altre parole, un proxy sa esattamente cosa viene delegato.
Decorator
:
Inizia praticamente come Proxy
con un'interfaccia:
public interface JobSeeker {
int interviewScore();
}
e una sua attuazione:
class Newbie implements JobSeeker {
@Override
public int interviewScore() {
return 10;
}
}
E ora vogliamo aggiungere un candidato più esperto, che aggiunge il punteggio del colloquio più quello di un altro JobSeeker
:
@RequiredArgsConstructor
public class TwoYearsInTheIndustry implements JobSeeker {
private final JobSeeker jobSeeker;
@Override
public int interviewScore() {
return jobSeeker.interviewScore() + 20;
}
}
Notate come ho detto che più quello di un altro cercatore di lavoro , no Newbie
. A Decorator
non sa esattamente cosa sta decorando, conosce solo il contratto di quell'istanza decorata (lo sa JobSeeker
). Prendi nota che questo è diverso da a Proxy
; che, al contrario, sa esattamente cosa sta decorando.
Potresti chiederti se c'è davvero qualche differenza tra i due modelli di design in questo caso? E se provassimo a scrivere Decorator
come Proxy
?
public class TwoYearsInTheIndustry implements JobSeeker {
private final Newbie newbie = new Newbie();
@Override
public int interviewScore() {
return newbie.interviewScore() + 20;
}
}
Questa è sicuramente un'opzione ed evidenzia quanto vicini siano questi schemi; sono ancora intesi per diversi scenari come spiegato nelle altre risposte.