问题
Can you give any good explanation what is the difference between Proxy and Decorator?
The main difference I see is that when we assume that Proxy uses composition and Decorator uses aggregation then it seems to be clear that by using multiple (one or more) Decorators you can modify/ add functionalities to pre-existing instance (decorate), whereas Proxy has own inner instance of proxied class and delegates to it adding some additional features (proxy behaviour).
The question is - Does Proxy created with aggregation is still Proxy or rather Decorator? Is it allowed (by definition in GoF patterns) to create Proxy with aggregation?
回答1:
Decorator Pattern focuses on dynamically adding functions to an object, while Proxy Pattern focuses on controlling access to an object.
EDIT:-
Relationship between a Proxy and the real subject is typically set at compile time, Proxy instantiates it in some way, whereas Decorator is assigned to the subject at runtime, knowing only subject's interface.
回答2:
The accepted answer is not quite correct. The real difference is not ownership (composition versus aggregation), but rather type-information.
A Decorator is always passed its delegatee. A Proxy might create it himself, or he might have it injected.
But a Proxy always knows the (more) specific type of the delegatee. In other words, the Proxy and its delegatee will have the same base type, but the Proxy points to some derived type. A Decorator points to its own base type. Thus, the difference is in compile-time information about the type of the delegatee.
In a dynamic language, if the delegatee is injected and happens to have the same interface, then there is no difference.
The answer to your question is "Yes".
回答3:
Decorator get reference for decorated object (usually through constructor) while Proxy responsible to do that by himself.
Proxy may not instantiate wrapping object at all (like this do ORMs to prevent unnecessary access to DB if object fields/getters are not used) while Decorator always hold link to actual wrapped instance.
Proxy usually used by frameworks to add security or caching/lazing and constructed by framework (not by regular developer itself).
Decorator usually used to add new behavior to old or legacy classes by developer itself based on interface rather then actual class (so it work on wide range of interface instances, Proxy is around concrete class).
回答4:
Key differences:
- Proxy provides the same interface. Decorator provides an enhanced interface.
- Decorator and Proxy have different purposes but similar structures. Both describe how to provide a level of indirection to another object, and the implementations keep a reference to the object to which they forward requests.
- Decorator can be viewed as a degenerate Composite with only one component. However, a Decorator adds additional responsibilities - it isn't intended for object aggregation.
- Decorator supports recursive composition
- The Decorator class declares a composition relationship to the LCD (Lowest Class Denominator) interface, and this data member is initialized in its constructor.
- Use Proxy for lazy initialization, performance improvement by caching the object and controlling access to the client/caller
Sourcemaking article quotes the similarities and differences in excellent way.
Related SE questions/links:
When to Use the Decorator Pattern?
What is the exact difference between Adapter and Proxy patterns?
回答5:
Proxy and Decorator differ in purpose and where they focus on the internal implementation. Proxy is for using a remote, cross process, or cross-network object as if it were a local object. Decorator is for adding new behavior to the original interface.
While both patterns are similar in structure, the bulk of the complexity of Proxy lies in ensuring proper communications with the source object. Decorator, on the other hand, focuses on the implementation of the added behavior.
回答6:
Took a while to figure out this answer and what it really means. A few examples should make it more clear.
Proxy
first:
public interface Authorization {
String getToken();
}
And :
// goes to the DB and gets a token for example
public class DBAuthorization implements Authorization {
@Override
public String getToken() {
return "DB-Token";
}
}
And there is a caller of this Authorization
, a pretty dumb one:
class Caller {
void authenticatedUserAction(Authorization authorization) {
System.out.println("doing some action with : " + authorization.getToken());
}
}
Nothing un-usual so far, right? Obtain a token from a certain service, use that token. Now comes one more requirement to the picture, add logging: meaning log the token every time. It's simple for this case, just create a 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;
}
}
How would we use that?
public static void main(String[] args) {
LoggingDBAuthorization loggingDBAuthorization = new LoggingDBAuthorization();
Caller caller = new Caller();
caller.authenticatedUserAction(loggingDBAuthorization);
}
Notice that LoggingDBAuthorization
holds an instance of DBAuthorization
. Both LoggingDBAuthorization
and DBAuthorization
implement Authorization
.
- A proxy will hold some concrete implementation (
DBAuthorization
) of the base interface (Authorization
). In other words a Proxy knows exactly what is being proxied.
Decorator
:
It starts pretty much the same as Proxy
, with an interface:
public interface JobSeeker {
int interviewScore();
}
and an implementation of it:
class Newbie implements JobSeeker {
@Override
public int interviewScore() {
return 10;
}
}
And now we want to add a more experienced candidate, that adds it's interview score plus the one from another JobSeeker
:
@RequiredArgsConstructor
public class TwoYearsInTheIndustry implements JobSeeker {
private final JobSeeker jobSeeker;
@Override
public int interviewScore() {
return jobSeeker.interviewScore() + 20;
}
}
Notice how I said that plus the one from another JobSeeker, not Newbie
. A Decorator
does not know exactly what it is decorating, it knows just the contract of that decorated instance (it knows about JobSeeker
). Take note here that this is unlike a Proxy
; that, in contrast, knows exactly what it is decorating.
You might question if there is actually any difference between the two design patterns in this case? What if we tried to write the Decorator
as a Proxy
?
public class TwoYearsInTheIndustry implements JobSeeker {
private final Newbie newbie = new Newbie();
@Override
public int interviewScore() {
return newbie.interviewScore() + 20;
}
}
This is definitely an option and highlights how close these patterns are; they are still intended for different scenarios as explained in the other answers.
回答7:
Proxy provides the same interface to the wrapped object, Decorator provides it with an enhanced interface, and Proxy usually manages the life cycle of its service object on its own, whereas the composition of Decorators is always controlled by the client.
来源:https://stackoverflow.com/questions/18618779/differences-between-proxy-and-decorator-pattern