如何做代理,装饰,适配器和桥模式有所不同?
-
20-08-2019 - |
题
我一直在寻找代理模式,并对我来说,这似乎是一个很喜欢的设计师的适配器和桥模式。我误解的东西吗?有什么区别?为什么我会用代理模式与其他人呢?你如何使用他们过去在现实世界中的项目?
解决方案
代理,装饰,适配器和桥梁的所有变化形式上的"包装"一类。但他们使用的是不同的。
代理 可当你想到懒化的对象,或隐瞒事实,你打电话远程服务,或者控制的访问对象。
装饰 也被称为"智能代理。" 这是用来当你需要添加功能的一个目的,但不是通过延伸,目的类型。这可以让你这样做在运行时间。
适配器 是用来当你有一个抽象的接口,并且你想要的地图接口到另一个对象有类似的功能作用,但一个不同的接口。
桥 非常类似于适配器,但我们呼吁它桥的时候你确定的抽象的界面和基础实施。I.e。你不适应某些传统或第三方代码,你的设计的所有代码但你需要能够交换了不同的方式实现的。
正面 是一个更高的级别(阅读:更简单)接口的一个子系统的一个或更多类。假设你有一个复杂的概念,需要多个对象来表示。更改后,设置的对象是令人困惑,因为你总是不知道其对象具有法你需要的呼吁。这就是时间去写一个门面提供高级别的方法为所有复杂的操作可以做,以集合的对象。例如:一领域模型,用于学校部分,方法一样
countStudents()
,reportAttendance()
,assignSubstituteTeacher()
, 等等。
其他提示
所以是他们的结构。
代理 和 装饰 两者具有相同的接口,作为他们的包裹,但代理创建一个实例引擎盖下的,而需要装饰的一个实例,在构造。
适配器 和 正面 两者都有一个不同的接口比什么他们包裹。但转接器来自一个现有的接口,而立面创建一个新的接口。
桥 和 适配器 这两点在一个现有的类型。但桥点将在一个抽象的类型,以及适配器可能指向一个具体的类型。桥会让你对执行在运行时,而适配器,通常不会。
我采取这一议题。
所有四种模式有很多共同点,所有四个有时非正式地称为包装或包装的模式。所有使用组成,包装主题,并授权执行的问题在某些时候,做映一个方法调到另一个。他们用备用客户端的必要性具有构建一个不同的对象和复制所有相关的数据。如果明智地使用,他们保存的记忆和处理器。
通过促进松散耦合他们一旦稳定的代码较少受到不可避免的变化和更好的可读于同开发。
适配器
适配器适应问题(adaptee)向一个不同的接口。这种方式,我们可以添加对象被放置到一个集合名义上不同的类型。
适配器获得的唯一相关方法的客户,可以限制所有其他人,揭示使用意图用于特定情况下,如适应外部图书馆,使它的出现较大和更集中于我们的应用程序的需要。适配器以增加可读性和自我介绍我们的代码。
适配器屏蔽的一个团队自挥发性码从其他小组;一个生命的救主的工具,在处理离岸队;-)
较少提及的目的,它以防止受类从多余的注释。有许多框架的基础上注释这将成为更重要的使用情况。
适配器能帮助得到解Java限制的唯一继承。它可能结合几个adaptees下一个信封给印象的多个继承。
代码明智的,适配器是"薄"。它不应该增加多少代码中的adaptee类,除了简单地呼吁adaptee方法以及偶尔的数据的转换有必要做出这样的呼吁。
没有许多良好的转接器的实例在JAVA或基本的图书馆。应用程序开发者创造适配器,以适应库应用程序的具体的接口。
装饰
装饰并不仅代表,不仅有地图的一种方法的另一个,他们做得更多,它们修改行为的一些问题的方法,它可以决定不打电话主题方法在所有,委派到不同对象,帮助对象。
装修通常添加(透明)的功能包的对象样的记录、加密、格式、或压缩到的主题。这一新功能可以带来很多新的编码。因此,装修通常是从"胖"然后适配器。
装饰必须是分类的主题的界面。他们可以使用透明,而不是它的主题。见BufferedOutputStream,它仍然是使用的输出流,并可以这样使用。这是一个重大的技术差异,从适配器。
文书的实例整个装修工人的家庭是很容易在JAVA-Java IO.所有类似的 BufferedOutputStream, FilterOutputStream 和 分布式架构 是装饰的 使用的输出流.他们可以是洋葱分层,其中一个装潢装饰再次,增加更多的功能。
代理
代理不是一个典型的包装。被包裹的目的,代理问题,可能尚不存在的时代创造的。代理常会造成其国内。它可以是一个沉重的物体上创建的需求,或者它是遥远的目在不同JVM或不同的网络节点,甚至非Java对象,一个组件在当地的代码。它没有必要的包裹或委派到另一个对象。
最典型的例子是遥远的代理人,重对象的初始化和访问的代理。
远程代理主题是在远程服务器、不同JVM或甚至不 Java系统。代理翻译方法的呼吁RMI/REST/皂电话或 无论是必要的,屏蔽客户接触到底层 技术。
懒惰的负荷代理充分初始化的目的只有第一次使用或 第一个密集的使用情况。
访问的代理控制进入的主题。
正面
正面是密切相关的设计原理至少知识(法的Demeter).正面是非常类似于适配器。他们两个包裹,他们两个地图的一个目到另一个,但他们在不同的意图。外墙平的复杂结构的一个主题,复杂的对象图,从而简化了访问一个复杂的结构。
外墙环绕一个复杂的结构,提供一个平坦的接口。这可以防止客户对象遭受到内部关系的主题结构,因此促进松散耦合。
桥
更复杂的变型适配器模式,不仅执行各不相同,但还抽象概念。它增加了一个更间接的代表团。额外的代表团的桥梁。它分离器即使从适应的接口。它增加了复杂性超过任何其它其他包裹的模式,因此适用与照顾。
差异的构造
模式差别也很明显的时候看他们的构造方法。
代理 是不是环绕现有的对象。没有主题在构造。
装饰 和 适配器 不包裹已经存在的对象,通常是这样的
设在构造。正面 构造需要根元素的一个整体对象图,否则它看起来 同样的,作为适配器。
现实生活的例子– 修订调动适配器.这器的映射的一个简单的平级到更复杂的结构所需的外部和防止"污染"主题类过多的注释。
所有好的答案专家已经解释了什么是否每个模式。
我 装饰 关键点。
装饰:
- 添加行为的对象在运行时间.继承遗产的关键是实现这一功能,这是这两个优点和缺点的这种模式。
- 它的修改 行为 的接口。
例如(与chaining): java.io
包装类别有关的 InputStream
& OutputStream
接口
FileOutputStream fos1 = new FileOutputStream("data1.txt");
ObjectOutputStream out1 = new ObjectOutputStream(fos1);
代理:
- 用于延迟初始化、性能的改进通过高速缓存的目的和控制对客户/叫.它可以提供替代性行为或称之为真正的对象。在此过程中,它可以创造新的对象。
- 不像 装饰, ,允许链接的对象,代理 不允许链接。
例如: java.rmi
包装类。
适配器:
- 它允许两个不相关的接口一起工作,通过不同的对象, 可能扮演相同的角色。
- 它修改原始接口.
例如 java.io.InputStreamReader
(InputStream
返回 Reader
)
桥:
- 它允许抽象和实现独立变化.
- 它使用 组成有超过继承.
例如集合中的类 java.util
. List
通过实施 ArrayList
.
关键的注意事项:
- 适配器 提供了一个不同的接口,以其主题。 代理 提供了相同的接口。 装饰 提供了一个增强型界面。
- 适配器 变化的一个目的接口, 装饰 增强对象的责任。
- 装饰 和 代理 具有不同的目的,但类似的结构
- 适配器 使事情变得工作之后,他们设计; 桥 让他们的工作之前他们。
- 桥 旨在最前面,让的抽象和实现独立变化。 适配器 是进行改装,使无关的课程的工作在一起
- 装饰 目的是让你加入的责任对象没有子类化。
看一看大SE问题/条款有关例子的各种设计图案
这是从报价 Head First设计模式
解释属于预定。实施例属于我。
装饰 - 不改变接口,但增加了责任。假设你有车界面, 当你实现这个对汽车的不同模式(S,SV,SL),您可能需要为添加更多的责任对于某些型号。等具有天窗,安全气囊等。
<强>适配器强> - 一个接口转换到另一个。你有车的界面和你希望它像吉普车行动。所以,你坐的车,对其进行修改,变成了一辆吉普车。的由于它不是一个真正的吉普车。但就像一个吉普车。强>
<强>门面强> - 使接口更简单。假设你有汽车,飞机,轮船接口。其实你需要的是把人从一个地方到另一个类。你想门面来决定使用什么车辆。然后你收集所有的接口引用下的1把伞,让它决定/授人以保持它的简单。
头第一:“A门面不仅简化的接口,它分离客户端从子系统 的组成部分。 外墙和适配器可以包装多种类型,但门面的目的是为了简化,同时 适配器的是到接口转换成不同的东西。“
所有的四种模式涉及包装内目/课外一个,所以他们都非常相似的结构.我将概述差异的目的:
- 代理 封装了访问以外以内。
- 装饰 修改或者延伸的行为的内部与外。
- 适配器 转换接口,从内到外。
- 桥 分隔成不变的部分的行为(外)从可变或依赖于平台的一部分(内部).
并且通过接口变化之间的内部和外部的对象:
- 在 代理 接口都是相同的。
- 在 装饰 接口都是相同的。
- 在 适配器 接口是不同的正式的,但符合同样的目的。
- 在 桥 接口是不同的概念.
使用Web服务时,我用它经常。代理模式或许应该被重命名为更加务实,比如“包装图案。”我也有一个库,代理到MS Excel,这使得它很容易使Excel自动运行,而不必担心背景细节,例如:版本被安装(如果有的话)。
说到详细实施方案中,我发现代理和装饰,适配器,门面之间的差...在常见的实施这些模式有由包围对象缠绕的目标对象的。客户端使用封装对象,而不是目标对象。而目标对象实际上里面的一些封闭对象的方法发挥重要作用。
然而,在代理服务器的情况下,包围目的可以通过本身玩一些方法中,它仅仅初始化目标对象时客户端调用一些它需要目标对象采取部分的方法。这是延迟初始化。在其他模式的情况下,包围对象虚拟地基于目标物体上。所以目标对象总是与在构造/ setter方法包围对象初始化沿着。
另一件事,代理不正是一个目标做什么,而其他的模式添加更多的功能目标。
我想添加实例法案Karwing答复(这是伟大的顺便说一句.) 我还添加一些关键差异的执行情况,我觉得是失踪
援引的部分是从回答中[https://stackoverflow.com/a/350471/1984346] (法案Karwing)
代理,装饰,适配器和桥梁的所有变化形式上的"包装"一类。但他们使用的是不同的。
- 代理 可当你想到懒化的一个目的,或 隐瞒事实,你打电话远程服务,或者控制的访问 的对象。
ProxyClass和ObjectClass也就是代理,应该实现同样的接口,使他们互换
例代理昂贵的对象
class ProxyHumanGenome implements GenomeInterface {
private $humanGenome = NULL;
// humanGenome class is not instantiated at construct time
function __construct() {
}
function getGenomeCount() {
if (NULL == $this->humanGenome) {
$this->instantiateGenomeClass();
}
return $this->humanGenome->getGenomeCount();
}
}
class HumanGenome implement GenomeInterface { ... }
- 装饰 也被称为"智能代理。" 这是用来当你要 添加功能的一个目的,但不是通过延伸,目的 类型。这可以让你这样做在运行时间。
DecoratorClass应(可能)实施扩展接口的ObjectClass.所以ObjectClass可以替代DecoratorClass,但不反之亦然。
例增加另外的功能
class DecoratorHumanGenome implements CheckGenomeInterface {
// ... same code as previous example
// added functionality
public function isComplete() {
$this->humanGenome->getCount >= 21000
}
}
interface CheckGenomeInterface extends GenomeInterface {
public function isComplete();
}
class HumanGenome implement GenomeInterface { ... }
- 适配器 是用来当你有一个抽象的接口,并且你想要 地图界面,另一个对象有类似的功能 的作用,但一个不同的接口。
Implentation的差异代理,装饰,适配器
适配器提供了一个不同的接口,以其主题。代理提供了相同的接口。装饰提供了一个增强型界面。
桥 非常类似于适配器,但我们称它为大桥时 确定的抽象的界面和基础实施。I.e。你不适应某些传统或第三方代码,你在 设计师的所有代码,但需要时可以交换出来 不同的实现。
正面 是一个更高的级别(阅读:更简单)接口的一个子系统 一个或更多类。假设你有一个复杂的概念,需要 多个对象来表示。更改后,设置的对象 是混乱的,因为你总是不知道其对象具有的 方法需要的呼吁。这就是时间去写一个门面 提供了高水平的方法为所有复杂的操作可以做 为收集对象。例如:一领域模型的学校 部分,方法一样
countStudents()
,reportAttendance()
,assignSubstituteTeacher()
, 等等。
大多数的信息,在这个答案是从 https://sourcemaking.com/design_patterns, 我建议作为一个 很好的资源 设计图案。
我相信代码会给出一个明确的想法,(补充别人的答案也一样)。请参考下面,(聚焦的类型的一个类实现和包装纸)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestConsole
{
class Program
{
static void Main(string[] args)
{
/* Proxy */
Console.WriteLine(Environment.NewLine);
Console.WriteLine("PROXY");
Console.WriteLine(Environment.NewLine);
//instead of creating here create using a factory method, the facory method will return the proxy
IReal realProxy = new RealProxy();
Console.WriteLine("calling do work with the proxy object ");
realProxy.DoWork();
Console.WriteLine(Environment.NewLine);
Console.WriteLine("ADAPTER");
Console.WriteLine(Environment.NewLine);
/*Adapter*/
IInHand objectIHave = new InHand();
Api myApi = new Api();
//myApi.SomeApi(objectIHave); /*I cant do this, use a adapter then */
IActual myAdaptedObject = new ActualAdapterForInHand(objectIHave);
Console.WriteLine("calling api with my adapted obj");
myApi.SomeApi(myAdaptedObject);
Console.WriteLine(Environment.NewLine);
Console.WriteLine("DECORATOR");
Console.WriteLine(Environment.NewLine);
/*Decorator*/
IReady maleReady = new Male();
Console.WriteLine("now male is going to get ready himself");
maleReady.GetReady();
Console.WriteLine(Environment.NewLine);
IReady femaleReady = new Female();
Console.WriteLine("now female is going to get ready her self");
femaleReady.GetReady();
Console.WriteLine(Environment.NewLine);
IReady maleReadyByBeautician = new Beautician(maleReady);
Console.WriteLine("now male is going to get ready by beautician");
maleReadyByBeautician.GetReady();
Console.WriteLine(Environment.NewLine);
IReady femaleReadyByBeautician = new Beautician(femaleReady);
Console.WriteLine("now female is going to get ready by beautician");
femaleReadyByBeautician.GetReady();
Console.WriteLine(Environment.NewLine);
Console.ReadLine();
}
}
/*Proxy*/
public interface IReal
{
void DoWork();
}
public class Real : IReal
{
public void DoWork()
{
Console.WriteLine("real is doing work ");
}
}
public class RealProxy : IReal
{
IReal real = new Real();
public void DoWork()
{
real.DoWork();
}
}
/*Adapter*/
public interface IActual
{
void DoWork();
}
public class Api
{
public void SomeApi(IActual actual)
{
actual.DoWork();
}
}
public interface IInHand
{
void DoWorkDifferently();
}
public class InHand : IInHand
{
public void DoWorkDifferently()
{
Console.WriteLine("doing work slightly different ");
}
}
public class ActualAdapterForInHand : IActual
{
IInHand hand = null;
public ActualAdapterForInHand()
{
hand = new InHand();
}
public ActualAdapterForInHand(IInHand hnd)
{
hand = hnd;
}
public void DoWork()
{
hand.DoWorkDifferently();
}
}
/*Decorator*/
public interface IReady
{
void GetReady();
}
public class Male : IReady
{
public void GetReady()
{
Console.WriteLine("Taking bath.. ");
Console.WriteLine("Dress up....");
}
}
public class Female : IReady
{
public void GetReady()
{
Console.WriteLine("Taking bath.. ");
Console.WriteLine("Dress up....");
Console.WriteLine("Make up....");
}
}
//this is a decorator
public class Beautician : IReady
{
IReady ready = null;
public Beautician(IReady rdy)
{
ready = rdy;
}
public void GetReady()
{
ready.GetReady();
Console.WriteLine("Style hair ");
if (ready is Female)
{
for (int i = 1; i <= 10; i++)
{
Console.WriteLine("doing ready process " + i);
}
}
}
}
}
设计图案不是数学,它是本领域和软件工程的组合。没有什么比这个需求量的,你必须使用代理服务器,桥梁等创建设计模式来解决问题。如果可能的设计问题,然后使用它。根据经验,你会知道具体的问题,要使用的模式。如果你是在坚实的设计原则好,你就已经实现了设计模式,不知道它是模式。常见的例子是statergy和工厂模式
因此更专注于固体desighn原则,清洁编码原理和TTD