我正在查看代理模式,对我来说,它看起来非常像装饰器、适配器和桥接模式。我是不是误解了什么?有什么不同?为什么我要使用代理模式而不是其他模式?在过去的实际项目中,您是如何使用它们的?
当前回答
这是引用自 头部优先的设计模式
定义属于书。例子属于我。
装饰器——不改变界面,但增加了责任。假设你有一个汽车界面, 当您为不同型号的汽车(s, sv, sl)实现此功能时,您可能需要为某些型号添加更多的职责。比如有天窗,安全气囊等。
适配器—将一个接口转换为另一个接口。你有一个汽车界面,你想让它像吉普车一样工作。所以你把车开过来,改装成吉普车。因为这不是真正的吉普车。但它就像一辆吉普车。
Facade -使界面更简单。假设你有汽车、飞机、轮船接口。实际上,你所需要的只是一个将人从一个位置发送到另一个位置的类。你想让门面决定用什么车。然后将所有这些接口引用收集到一个保护伞下,并让它决定/委托以保持简单。
首先:“facade不仅简化了接口,还将客户端与子系统解耦 的组件。 外观和适配器可以包装多个类,但是外观的目的是简化 适配器的作用是将接口转换为不同的东西。”
其他回答
我对这个问题的看法。
这四种模式有很多共同之处,这四种模式有时都被非正式地称为包装器或包装模式。所有这些都使用组合,包装主题,并在某些时候将执行委托给主题,将一个方法调用映射到另一个方法调用。它们使客户不必构造一个不同的对象并复制所有相关数据。如果使用得当,它们可以节省内存和处理器。
通过促进松耦合,它们使曾经稳定的代码更少地暴露在不可避免的更改中,对其他开发人员来说可读性更好。
适配器
适配器使主题(adaptee)适应不同的接口。通过这种方式,我们可以将对象添加到名义上不同类型的集合中。
适配器只向客户端公开相关的方法,可以限制所有其他方法,揭示特定上下文的使用意图,比如适应外部库,使其看起来不那么通用,更专注于我们的应用程序需求。适配器增加了代码的可读性和自描述性。
适配器保护一个团队不受来自其他团队的易变代码的影响;在处理离岸团队时的救星工具;-)
较少提及的目的是防止主题类的注释过多。有这么多基于注解的框架,这就变得越来越重要了。
适配器有助于绕过Java只能单一继承的限制。它可以在一个信封下组合多个改编,给人一种多重遗传的印象。
在代码方面,Adapter是“瘦”的。它不应该向adaptee类添加太多代码,除了简单地调用adaptee方法和偶尔进行此类调用所需的数据转换之外。
JDK或基本库中没有很多好的适配器示例。应用程序开发人员创建适配器,使库适应应用程序特定的接口。
装饰
Decorator不仅仅是委托,不仅仅是将一个方法映射到另一个,它们做的更多,它们修改一些subject方法的行为,它可以决定不调用subject方法,委托给一个不同的对象,一个helper对象。
装饰器通常向包装对象添加(透明的)功能,如日志记录、加密、格式化或压缩主题。这个新功能可能会带来很多新代码。因此,装饰器通常比适配器“胖”得多。
Decorator必须是subject接口的子类。它们可以透明地使用,而不是其主题。参见BufferedOutputStream,它仍然是OutputStream,可以这样使用。这是与适配器的主要技术区别。
整个装饰器家族的教科书示例很容易在JDK - Java IO中。所有类,如BufferedOutputStream, FilterOutputStream和ObjectOutputStream都是OutputStream的装饰器。它们可以是洋葱层状的,其中一个装饰器被再次装饰,增加更多的功能。
代理
代理不是典型的包装器。被包装的对象(代理主题)在创建代理时可能还不存在。代理通常在内部创建它。它可能是按需创建的重载对象,也可能是不同JVM或不同网络节点中的远程对象,甚至是非java对象,本机代码中的组件。它根本不需要包装或委托给另一个对象。
最典型的例子是远程代理、重对象初始化器和访问代理。
远程代理-主题在远程服务器上,不同的JVM甚至非 Java系统。代理将方法调用转换为RMI/REST/SOAP调用或 无论需要什么,保护病人不受潜在危险的影响 技术。 惰性加载代理-完全初始化对象只有第一次使用或 第一次密集使用。 访问代理-控制对主题的访问。
外观
立面与设计的最小知识原则(得墨忒耳定律)密切相关。 Facade非常类似于Adapter。它们都是包装,都是将一个对象映射到另一个对象,但它们的意图不同。立面扁平化了复杂结构的主题,复杂的对象图形,简化了对复杂结构的访问。
Facade包装了一个复杂的结构,为其提供了一个平面接口。这可以防止客户端对象暴露于主题结构中的内部关系,从而促进松耦合。
桥
适配器模式的更复杂变体,不仅实现不同,而且抽象也不同。它为委托增加了另一种间接方式。额外的代表团是一座桥梁。它甚至从适配接口中分离了适配器。它比其他任何包装模式都增加了更多的复杂性,因此应用时要小心。
构造函数的差异
在查看它们的构造函数时,模式差异也很明显。
代理没有包装现有对象。构造函数中没有主语。 装饰器和适配器包装已经存在的对象,这是典型的 在构造函数中提供。 外观构造函数取整个对象图的根元素,否则看起来 与Adapter相同。
真实的例子——JAXB编组适配器。该适配器的目的是将简单的平面类映射到外部所需的更复杂的结构,并防止用过多的注释“污染”主题类。
所有来自专家的好答案都已经解释了每种模式代表什么。
我将装饰关键点。
装饰:
在运行时向对象添加行为。继承是实现此功能的关键,这是此模式的优点和缺点。 它修改了界面的行为。
例如(带链接):java。io包类与InputStream和OutputStream接口相关
FileOutputStream fos1 = new FileOutputStream("data1.txt");
ObjectOutputStream out1 = new ObjectOutputStream(fos1);
代理:
使用它进行延迟初始化,通过缓存对象和控制对客户端/调用者的访问来提高性能。它可以提供替代行为或调用真实对象。在此过程中,它可能会创建新的Object。 与Decorator(允许对象链接)不同,Proxy不允许对象链接。
例如:java。Rmi包类。
适配器:
它允许两个不相关的接口通过不同的对象一起工作,可能扮演相同的角色。 对原有界面进行修改。
例如:java.io.InputStreamReader (InputStream返回Reader)
桥:
它允许抽象和实现独立变化。 它使用复合而不是继承。
例如,java.util中的集合类。由ArrayList实现的List。
关键笔记:
Adapter provides a different interface to its subject. Proxy provides the same interface. Decorator provides an enhanced interface. Adapter changes an object's interface, Decorator enhances an object's responsibilities. Decorator and Proxy have different purposes but similar structures Adapter makes things work after they're designed; Bridge makes them work before they are. Bridge is designed up-front to let the abstraction and the implementation vary independently. Adapter is retrofitted to make unrelated classes work together Decorator is designed to let you add responsibilities to objects without subclassing.
看看关于各种设计模式示例的优秀SE问题/文章
什么时候使用装饰器模式?
什么时候使用桥接模式?它与适配器模式有何不同?
代理模式和装饰模式的区别
这是引用自 头部优先的设计模式
定义属于书。例子属于我。
装饰器——不改变界面,但增加了责任。假设你有一个汽车界面, 当您为不同型号的汽车(s, sv, sl)实现此功能时,您可能需要为某些型号添加更多的职责。比如有天窗,安全气囊等。
适配器—将一个接口转换为另一个接口。你有一个汽车界面,你想让它像吉普车一样工作。所以你把车开过来,改装成吉普车。因为这不是真正的吉普车。但它就像一辆吉普车。
Facade -使界面更简单。假设你有汽车、飞机、轮船接口。实际上,你所需要的只是一个将人从一个位置发送到另一个位置的类。你想让门面决定用什么车。然后将所有这些接口引用收集到一个保护伞下,并让它决定/委托以保持简单。
首先:“facade不仅简化了接口,还将客户端与子系统解耦 的组件。 外观和适配器可以包装多个类,但是外观的目的是简化 适配器的作用是将接口转换为不同的东西。”
我相信代码会给出一个清晰的想法(补充其他答案)。请参见下面,(关注类实现和包装的类型)
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);
}
}
}
}
}
在使用web服务时,我经常使用它。代理模式可能应该重命名为更实用的东西,比如“包装器模式”。我也有一个库,是一个代理到MS Excel。它使自动化Excel变得非常容易,而不必担心背景细节,如安装了什么版本(如果有的话)。