Łuk*_*ski 108 oop design-patterns decorator proxy-pattern
你能解释一下Proxy和Decorator之间的区别吗?
我看到的主要区别在于,当我们假设Proxy使用合成而Decorator使用聚合时,似乎很清楚通过使用多个(一个或多个)装饰器,您可以修改/添加功能到预先存在的实例(装饰),而代理有自己的代理类的内部实例,并委托给它添加一些额外的功能(代理行为).
是个问题-是否代理与聚集创造仍然是代理还是相当装饰?是否允许(通过GoF模式中的定义)创建具有聚合的代理?
cdu*_*001 95
接受的答案并不完全正确.真正的区别不是所有权(构成与聚合),而是类型信息.
一个装饰是始终通过其代理方.一个代理 可能会创建它自己,或者他可能有它注入.
但是代理 总是知道委托者的(更多)特定类型.换句话说,Proxy及其代理人将具有相同的基本类型,但Proxy指向某些派生类型.一个装饰指向其自身的基本类型.因此,不同之处在于有关被委派者类型的编译时信息.
在动态语言中,如果被委托者被注入并且碰巧具有相同的接口,则没有区别.
你的问题的答案是"是".
Rah*_*thi 74
Decorator Pattern专注于向对象动态添加函数,而Proxy Pattern则专注于控制对对象的访问.
编辑:-
Proxy和真实主题之间的关系通常在编译时设置,Proxy以某种方式实例化,而Decorator在运行时分配给主题,只知道主题的接口.
jac*_*646 54
这是来自 GoF 的直接引述(第 216 页)。
尽管装饰器可以具有与代理类似的实现,但装饰器有不同的用途。装饰器向对象添加一个或多个职责,而代理控制对对象的访问。
代理的实现程度不同,就像装饰器一样。保护代理可以像装饰器一样实现。另一方面,远程代理将不包含对其真实主题的直接引用,而仅包含间接引用,例如“主机 ID 和主机上的本地地址”。虚拟代理将从间接引用(例如文件名)开始,但最终将获得并使用直接引用。
流行的答案表明代理知道其委托的具体类型。从这句话我们可以看出,这并不总是正确的。
GoF 中Proxy 和Decorator 的区别在于Proxy限制了客户端。装饰器没有。代理可以通过控制对功能的访问来限制客户端的行为;或者它可以通过执行客户端不可见和不知道的操作来限制客户端知道的内容。装饰器做相反的事情:它以客户端可见的方式增强其委托的功能。
我们可以说 Proxy 是一个黑盒,而 Decorator 是一个白盒。
在对比代理和装饰器时,包装器和委托之间的组合关系是错误的关注关系,因为组合是这两种模式的共同特征。包装器和客户端之间的关系是区分这两种模式的原因。
gav*_*koa 43
装饰器获取装饰对象的引用(通常通过构造函数),而Proxy负责自己做.
代理可能根本不实例化包装对象(如果没有使用对象字段/ getter,这样做是为了防止对DB进行不必要的访问),而Decorator总是保存到实际包装实例的链接.
框架通常使用代理来添加安全性或缓存/ lazing并由框架构建(而不是由常规开发人员自己构建).
Decorator通常用于通过开发人员本身基于接口而不是实际类向旧类或旧类添加新行为(因此它适用于各种接口实例,Proxy是围绕具体类).
Rav*_*abu 19
主要差异:
Sourcemaking文章以优秀的方式引用了相同点和不同点.
相关的SE问题/链接:
花了一段时间才弄清楚这个答案及其真正含义。几个例子应该可以更清楚地说明这一点。
Proxy第一的:
public interface Authorization {
String getToken();
}
Run Code Online (Sandbox Code Playgroud)
和 :
// goes to the DB and gets a token for example
public class DBAuthorization implements Authorization {
@Override
public String getToken() {
return "DB-Token";
}
}
Run Code Online (Sandbox Code Playgroud)
有一个调用者Authorization,一个非常愚蠢的调用者:
class Caller {
void authenticatedUserAction(Authorization authorization) {
System.out.println("doing some action with : " + authorization.getToken());
}
}
Run Code Online (Sandbox Code Playgroud)
到目前为止没有什么不寻常的,对吧?从某个服务获取令牌,并使用该令牌。现在又提出了一个要求,添加日志记录:意思是每次都记录令牌。对于这种情况很简单,只需创建一个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;
}
}
Run Code Online (Sandbox Code Playgroud)
我们将如何使用它?
public static void main(String[] args) {
LoggingDBAuthorization loggingDBAuthorization = new LoggingDBAuthorization();
Caller caller = new Caller();
caller.authenticatedUserAction(loggingDBAuthorization);
}
Run Code Online (Sandbox Code Playgroud)
请注意,它LoggingDBAuthorization 包含一个 的实例DBAuthorization。两者LoggingDBAuthorization兼而有之。DBAuthorization Authorization
DBAuthorization基本接口 () 的一些具体实现 () Authorization。换句话说,代理确切地知道正在代理的内容。Decorator:
它的开始与 几乎相同Proxy,有一个接口:
public interface JobSeeker {
int interviewScore();
}
Run Code Online (Sandbox Code Playgroud)
及其实现:
class Newbie implements JobSeeker {
@Override
public int interviewScore() {
return 10;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们想添加一位更有经验的候选人,将其面试分数加上另一位候选人的面试分数JobSeeker:
@RequiredArgsConstructor
public class TwoYearsInTheIndustry implements JobSeeker {
private final JobSeeker jobSeeker;
@Override
public int interviewScore() {
return jobSeeker.interviewScore() + 20;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意我是如何说的,再加上另一位求职者的说法,而不是 Newbie。ADecorator并不确切地知道它正在装饰什么,它只知道该装饰实例的契约(它知道JobSeeker)。请注意,这与 ; 不同Proxy。相比之下,它确切地知道它正在装饰什么。
您可能会问,在这种情况下,两种设计模式实际上是否有任何区别?如果我们尝试将 the 写成Decoratora 会怎么样Proxy?
public class TwoYearsInTheIndustry implements JobSeeker {
private final Newbie newbie = new Newbie();
@Override
public int interviewScore() {
return newbie.interviewScore() + 20;
}
}
Run Code Online (Sandbox Code Playgroud)
这绝对是一个选择,并强调了这些模式的接近程度;正如其他答案中所解释的,它们仍然适用于不同的场景。
代理和装饰器的目的不同,它们专注于内部实现的地方。代理用于像使用本地对象一样使用远程、跨进程或跨网络对象。装饰器用于向原始界面添加新行为。
虽然这两种模式在结构上相似,但 Proxy 的大部分复杂性在于确保与源对象的正确通信。另一方面,装饰器专注于添加行为的实现。
| 归档时间: |
|
| 查看次数: |
31000 次 |
| 最近记录: |