我在看代理模式,对我而言,它似乎很像装饰器,适配器和桥模式.我误会了什么吗?有什么不同?为什么我会使用Proxy模式而不是其他模式?你过去在现实世界的项目中如何使用它们?
代理,装饰器,适配器和桥都是"包装"类的变体.但他们的用途不同.
当您想要延迟实例化对象时,可以使用代理,或者隐藏您正在调用远程服务或控制对象访问的事实.
Decorator也被称为"智能代理".当您想要向对象添加功能时使用此功能,但不能通过扩展该对象的类型来使用.这允许您在运行时执行此操作.
当您具有抽象接口时,将使用适配器,并且您希望将该接口映射到具有类似功能角色但具有不同接口的另一个对象.
Bridge与Adapter非常相似,但是当您定义抽象接口和底层实现时,我们将其称为Bridge.即,您不适应某些遗留代码或第三方代码,您是所有代码的设计者,但您需要能够交换不同的实现.
Facade是一个更高级别(读取:更简单)的接口,用于一个或多个类的子系统.假设您有一个复杂的概念,需要多个对象来表示.对这组对象进行更改会让人感到困惑,因为您并不总是知道哪个对象具有您需要调用的方法.现在是编写Facade的时候了,它可以为您可以对对象集合执行的所有复杂操作提供高级方法.例如:一个域模型为学校部分,与类似的方法countStudents()
,reportAttendance()
,assignSubstituteTeacher()
,等.
正如比尔的回答所说,他们的用例是不同的.
他们的结构也是如此.
Proxy和Decorator都具有与其包装类型相同的接口,但代理在底层创建实例,而装饰器在构造函数中获取实例.
Adapter和Facade都有不同的界面.但适配器派生自现有接口,而外观则创建新接口.
Bridge和Adapter都指向现有类型.但是桥将指向抽象类型,并且适配器可能指向具体类型.该桥允许您在运行时配对实现,而适配器通常不会.
我对这个问题的看法.
所有四种模式都有很多共同点,所有这四种模式有时被非正式地称为包装器或包装器模式.所有使用组合,包装主题并在某个时刻将执行委托给主题,将一个方法调用映射到另一个方法调用.它们使客户无需必须构建不同的对象并复制所有相关数据.如果使用得当,它们可以节省内存和处理器.
通过促进松散耦合,他们可以使稳定的代码更少地暴露于不可避免的变化,并且对于其他开发人
适配器
适配器使主体(适配器)适应不同的接口.这样我们就可以将对象添加到名义上不同类型的集合中.
适配器仅向客户端公开相关方法,可以限制所有其他方法,显示特定上下文的使用意图,如调整外部库,使其看起来不那么通用,更专注于我们的应用程序需求.适配器提高了代码的可读性和自我描述.
适配器使一个团队免受其他团队的易变代码的攻击; 处理离岸团队时的救生员工具;-)
较少提及的目的是防止主题类过多的注释.有了这么多基于注释的框架,这就变得越来越重要了.
适配器有助于克服仅限单一继承的Java限制.它可以将几个适应者组合在一个信封下,给人以多重继承的印象.
代码方面,适配器是"瘦".除了简单地调用adaptee方法和进行此类调用所需的偶尔数据转换之外,它不应该向adaptee类添加太多代码.
JDK或基本库中没有很多好的适配器示例.应用程序开发人员创建适配器,以使库适应应用程序特定的接口
装饰
Decorator不仅委托,不仅将一个方法映射到另一个方法,它们做得更多,它们修改了一些主题方法的行为,它可以决定不调用主题方法,委托给不同的对象,一个辅助对象.
装饰器通常将(透明)功能添加到包装对象,如记录,加密,格式化或压缩到主题.这个新功能可能会带来很多新代码.因此,装饰器通常比适配器"更胖".
装饰器必须是主题界面的子类.它们可以透明地使用而不是它的主题.请参阅BufferedOutputStream,它仍然是OutputStream,可以这样使用.这是Adapters的主要技术差异.
JDK中的整个装饰器系列的教科书示例很容易 - Java IO.BufferedOutputStream,FilterOutputStream和ObjectOutputStream等所有类都是OutputStream的装饰器.它们可以是洋葱层,再一次装饰一个装饰,增加更多功能.
代理
代理不是典型的包装器.在创建代理时,包装对象(代理主题)可能尚不存在.代理通常在内部创建它.它可能是按需创建的繁重对象,也可能是不同JVM或不同网络节点中的远程对象,甚至是非Java对象(本机代码中的组件).它根本没有必要包装或委托给另一个对象.
最典型的例子是远程代理,重对象初始化器和访问代理.
远程代理 - 主题在远程服务器,不同的JVM甚至非Java系统上.代理将方法调用转换为RMI/REST/SOAP调用或任何需要的内容,从而防止客户端暴露于底层技术.
延迟加载代理 - 仅对第一次使用或第一次密集使用完全初始化对象.
访问代理 - 控制对主题的访问.
正面
立面与最小知识的设计原则(德米特定律)密切相关.Facade与Adapter非常相似.它们都包装,它们都将一个对象映射到另一个对象,但它们的意图不同.Facade展平了主题的复杂结构,复杂的对象图,简化了对复杂结构的访问.
Facade包裹着一个复杂的结构,为它提供了一个平面界面.这可以防止客户端对象暴露于主题结构中的内部关系,从而促进松耦合.
桥
适配器模式的更复杂的变体,其中不仅实现变化而且抽象.它为代表团增加了一个间接性.额外的授权是桥梁.它甚至可以从适配接口中解耦适配器.它比任何其他包装模式更增加复杂性,因此请小心使用.
构造函数的差异
在查看构造函数时,模式差异也很明显.
代理不包装现有对象.构造函数中没有主题.
Decorator和Adapter确实包装已经存在的对象,这通常
在构造函数中提供.
Facade构造函数获取整个对象图的根元素,否则它看起来与Adapter相同.
现实生活中的例子 - JAXB编组适配器.此适配器的用途是将简单的平面类映射到外部所需的更复杂的结构,并防止使用过多的注释"污染"主题类.
许多GoF模式存在很多重叠.它们都建立在多态性的力量之上,有时只在意图上有所不同.(战略与国家)
阅读Head First Design Patterns后,我对图案的理解增加了100倍.
我强烈推荐它!
专家们的所有好答案都已经解释了每种模式的含义.
我将装饰关键点.
装饰:
在运行时向对象添加行为.继承是实现此功能的关键,这是该模式的优点和缺点.
它修改了界面的行为.
例如(带链接):java.io
与InputStream
&OutputStream
interfaces 相关的包类
FileOutputStream fos1 = new FileOutputStream("data1.txt"); ObjectOutputStream out1 = new ObjectOutputStream(fos1);
代理:
通过缓存对象和控制对客户端/调用者的访问,将其用于延迟初始化,性能改进.它可以提供替代行为或调用真实对象.在此过程中,它可能会创建新的Object.
与允许链接对象的Decorator不同,Proxy 不允许链接.
例如:java.rmi
包类.
适配器:
它允许两个不相关的接口通过不同的对象一起工作,可能扮演相同的角色.
它修改了原始界面.
例如java.io.InputStreamReader
(InputStream
返回a Reader
)
桥:
它允许抽象和实现独立变化.
它使用组合而不是继承.
例如,收集课程java.util
.List
由...实施ArrayList
.
主要说明:
适配器为其主题提供不同的界面.代理提供相同的接口.Decorator提供增强的界面.
适配器更改了对象的界面, Decorator增强了对象的职责.
装饰器和代理具有不同的目的但结构相似
适配器在设计完成后使其工作; Bridge让它们在它们之前工作.
Bridge是预先设计的,让抽象和实现独立变化.改造适配器以使不相关的类一起工作
Decorator旨在让您在没有子类化的情况下向对象添加职责.
看看有关各种设计模式示例的精彩SE问题/文章
何时使用装饰器模式?
你什么时候使用桥模式?它与适配器模式有何不同?
代理和装饰模式之间的差异
它们非常相似,它们之间的界线很灰.我建议你阅读c2 wiki中的Proxy Pattern和Decorator Pattern条目.
这里的条目和讨论非常广泛,并且还链接到其他相关文章.顺便说一下,当想知道不同模式之间的细微差别时,c2 wiki非常出色.
为了总结c2条目,我会说装饰器添加/更改行为,但代理更多地与访问控制(延迟实例化,远程访问,安全性等)有关.但就像我说的那样,它们之间的界限是灰色的,我看到代理的引用很容易被视为装饰者,反之亦然.