我正在查看代理模式,对我来说,它看起来非常像装饰器、适配器和桥接模式。我是不是误解了什么?有什么不同?为什么我要使用代理模式而不是其他模式?在过去的实际项目中,您是如何使用它们的?


当前回答

说到细节实现,我发现代理和Decorator,适配器,Facade之间的区别…在这些模式的常见实现中,有一个被封闭对象包裹的目标对象。客户端使用外围对象而不是目标对象。目标对象实际上在一些封闭对象的方法中扮演着重要的角色。

而对于Proxy,外围对象可以自己扮演一些方法,它只是在客户端调用一些需要目标对象参与的方法时对目标对象进行初始化。这是惰性初始化。对于其他模式,封闭对象实际上是基于目标对象的。目标对象总是和构造函数/setter中的封闭对象一起初始化。

另一件事,代理所做的正是目标所做的,而其他模式则为目标添加了更多功能。

其他回答

我相信代码会给出一个清晰的想法(补充其他答案)。请参见下面,(关注类实现和包装的类型)

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);
                }

            }
        }
    }

}

它们非常相似,而且它们之间的线条是灰色的。我建议您阅读c2 wiki中的代理模式和装饰器模式条目。

那里的条目和讨论相当广泛,也链接到其他相关文章。顺便说一下,c2 wiki在了解不同模式之间的细微差别时非常有用。

总结c2项,我认为装饰器添加/更改行为,但代理与访问控制(延迟实例化,远程访问,安全等)有更多关系。但正如我所说,它们之间的界线是灰色的,我看到对代理的引用很容易被视为装饰器,反之亦然。

在使用web服务时,我经常使用它。代理模式可能应该重命名为更实用的东西,比如“包装器模式”。我也有一个库,是一个代理到MS Excel。它使自动化Excel变得非常容易,而不必担心背景细节,如安装了什么版本(如果有的话)。

所有来自专家的好答案都已经解释了每种模式代表什么。

我将装饰关键点。

装饰:

在运行时向对象添加行为。继承是实现此功能的关键,这是此模式的优点和缺点。 它修改了界面的行为。

例如(带链接):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问题/文章

什么时候使用装饰器模式?

什么时候使用桥接模式?它与适配器模式有何不同?

代理模式和装饰模式的区别

所有这四种模式都涉及到用外部对象/类包装内部对象/类,因此它们在结构上非常相似。我将通过目的来概述不同之处:

代理将访问从外部封装到内部。 装饰器用外部修改或扩展内部的行为。 适配器转换接口从内部到外部。 桥将行为的不变部分(外部)与变量或平台依赖部分(内部)分开。

通过内外物体之间的界面变化:

在代理接口中是相同的。 在Decorator接口中是相同的。 在适配器接口形式上不同,但实现相同的目的。 桥接接口在概念上是不同的。