您能否给出任何好的解释,Proxy和Decorator有什么区别?
我看到的主要区别是,当我们假设代理使用组合并且装饰器使用聚合时,那么很显然,通过使用多个(一个或多个)装饰器,您可以为预先存在的实例(装饰)修改/添加功能,而代理具有自己的代理类内部实例,并为其添加了一些附加功能(代理行为)的委托。
现在的问题是-不代理创建了聚集仍然是代理还是相当装饰?是否允许(按照GoF模式的定义)创建具有聚合的代理?
您能否给出任何好的解释,Proxy和Decorator有什么区别?
我看到的主要区别是,当我们假设代理使用组合并且装饰器使用聚合时,那么很显然,通过使用多个(一个或多个)装饰器,您可以为预先存在的实例(装饰)修改/添加功能,而代理具有自己的代理类内部实例,并为其添加了一些附加功能(代理行为)的委托。
现在的问题是-不代理创建了聚集仍然是代理还是相当装饰?是否允许(按照GoF模式的定义)创建具有聚合的代理?
Answers:
这是来自GoF的直接报价(第216页)。
尽管装饰器可以具有与代理类似的实现,但装饰器具有不同的用途。装饰器将一个或多个职责添加到对象,而代理控制对对象的访问。
代理的实现程度不同,如装饰器。保护代理可以完全像装饰器一样实现。另一方面,远程代理将不包含对其真实主题的直接引用,而仅包含间接引用,例如“主机ID和主机上的本地地址”。虚拟代理将以间接引用(例如文件名)开始,但最终将获得并使用直接引用。
流行的答案表明,代理知道代理的具体类型。从这句话中我们可以看出并非总是如此。
根据GoF,Proxy和Decorator之间的区别在于Proxy 限制了客户端。装饰器没有。代理可以通过控制对功能的访问来限制客户端的操作。否则可能会限制客户的了解通过执行看不见和未知的操作来的内容。装饰器的作用相反:装饰器以客户端可见的方式增强其代理的功能。
我们可以说代理是一个黑盒子,而装饰器是一个白盒子。
在将Proxy与Decorator进行对比时,包装器和委托之间的组合关系是错误的关系,因为组合是这两种模式的共同特征。包装器和客户端之间的关系是区分这两种模式的原因。
真正的区别不是所有权(组成与聚合),而是类型信息。
一个装饰是始终通过其代理方。一个代理 可能会创建它自己,或者他可能有它注入。
但是代理 总是知道委托人的(更多)特定类型。换句话说,代理服务器及其委托人将具有相同的基本类型,但是代理服务器指向某些派生类型。一个装饰指向其自身的基本类型。因此,区别在于有关委托人类型的编译时信息。
在动态语言中,如果委托被注入并且碰巧具有相同的接口,则没有区别。
您的问题的答案是“是”。
装饰器模式专注于向对象动态添加功能,而代理模式专注于控制对对象的访问。
编辑:-
代理与实际主题之间的关系通常在编译时设置,代理以某种方式实例化它,而Decorator在运行时分配给主题,仅知道主题的界面。
主要区别:
原始资料制作文章以出色的方式引用了异同。
相关的SE问题/链接:
花了一些时间弄清楚这个答案及其真正含义。一些例子应该使它更清楚。
Proxy
第一:
public interface Authorization {
String getToken();
}
和:
// goes to the DB and gets a token for example
public class DBAuthorization implements Authorization {
@Override
public String getToken() {
return "DB-Token";
}
}
而且有一个调用者Authorization
,一个很愚蠢的人:
class Caller {
void authenticatedUserAction(Authorization authorization) {
System.out.println("doing some action with : " + authorization.getToken());
}
}
到目前为止没有什么不寻常的,对吧?从某个服务获取令牌,然后使用该令牌。现在对图片提出了另一个要求,添加了日志记录:意味着每次都记录令牌。在这种情况下很简单,只需创建一个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;
}
}
我们将如何使用它?
public static void main(String[] args) {
LoggingDBAuthorization loggingDBAuthorization = new LoggingDBAuthorization();
Caller caller = new Caller();
caller.authenticatedUserAction(loggingDBAuthorization);
}
请注意,其中LoggingDBAuthorization
包含的实例DBAuthorization
。无论LoggingDBAuthorization
和DBAuthorization
实施 Authorization
。
DBAuthorization
包含基本接口(Authorization
)的一些具体实现()。换句话说,代理服务器确切知道要代理的内容。Decorator
:
它的开始与几乎相同Proxy
,但具有一个接口:
public interface JobSeeker {
int interviewScore();
}
及其实现:
class Newbie implements JobSeeker {
@Override
public int interviewScore() {
return 10;
}
}
现在我们想添加一个经验更丰富的候选人,那就是面试成绩加上另一个JobSeeker
:
@RequiredArgsConstructor
public class TwoYearsInTheIndustry implements JobSeeker {
private final JobSeeker jobSeeker;
@Override
public int interviewScore() {
return jobSeeker.interviewScore() + 20;
}
}
请注意,我怎么说,再加上另一个JobSeeker的那个,不是 Newbie
。A Decorator
并不确切知道它正在装饰什么,它只知道那个装饰实例的协定(它知道JobSeeker
)。请注意,这与Proxy
; 相反,它确切地知道它正在装饰什么。
您可能会问,在这种情况下,两种设计模式之间实际上是否存在差异?如果我们尝试将Decorator
as 写为该Proxy
怎么办?
public class TwoYearsInTheIndustry implements JobSeeker {
private final Newbie newbie = new Newbie();
@Override
public int interviewScore() {
return newbie.interviewScore() + 20;
}
}
这绝对是一个选择,它突出了这些模式之间的距离。如其他答案所述,它们仍然适用于不同的场景。