什么是代理设计模式?正如四人帮所定义的那样,代理设计模式为另一个对象提供了一个代理(代表其他参与者)或占位符来控制对它的访问。代理人的意思是“代替”或“代表”。在其最简单的形式中,我们可以将代理定义为充当其他事物的接口的类。代理可以附加到任何东西,例如网络连接、内存中的大对象、文件或其他一些昂贵或无法复制的资源。我们也可以说代理(Proxy)是客户端(Client)调用的对象,用来访问幕后的真实对象。这意味着,在代理设计模式中,一个类代表另一个类的功能。通过示例了解C#中的代理设计模式:查看下图以更好地理解C#中的代理设计模式。正如您在下图中看到的,当客户端想要使用真实对象的某些方法时,他/她需要通过代理对象。这意味着客户端将调用代理对象的方法,代理将负责调用真实对象的方法。代理类型:代理分为三种类型。它们如下。虚拟代理:虚拟代理是“昂贵创建”对象的占位符。真正的对象仅在客户端第一次请求或访问该对象时创建。远程代理:远程代理为驻留在不同地址空间中的对象提供本地表示。保护代理:保护代理控制对敏感对象的访问。代理对象在转发请求之前检查调用者是否具有所需的访问权限。代理设计模式的真实示例:见下图。在右侧,您可以看到银行,在左侧,您可以看到一个名叫Anurag的人。Anurag在银行有一个账户。早些时候,比如1960年,Anurag想从他的账户中取款。那么他要做的就是,他必须带着他的存折去银行。然后他必须填写表格并需要排队。轮到他时,他必须将表格和存折交给银行员工,然后银行员工验证表格和他的存折,如果一切正常,银行员工将所需的钱交给阿努拉格。假设Anurag现在想取钱。所以,他现在能做的,不是去银行,而是拿着银行卡去最近的ATM取款机。然后,他插入银行卡并输入PIN码和取款金额。然后ATM将与银行通信并验证代码和金额,如果一切正常,ATM将把钱交给Anurag。Anurag直接从ATM取款,无需前往银行。所以这里银行是真实对象,ATM是代理。我认为这是代理设计模式最好的真实例子。为什么我们需要C#中的代理设计模式?让我们以代理服务器为例来理解代理设计模式的必要性。位于客户端应用程序(例如Web浏览器)和真实服务器之间的服务器称为代理服务器。此代理服务器拦截所有传入的真实服务器请求,以查看它是否可以自己完成请求。如果不是,则它将请求转发到真实服务器。代理服务器有两个主要目标。它们如下:改进的性能:代理服务器可以大大提高应用程序的性能。这是因为它暂时保存了请求的结果。例如,假设我们有两个用户X和Y,他们想通过代理服务器访问特定的资源。首先,用户X请求特定资源(例如,员工列表)并将该资源缓存一段时间。后来,用户Y也请求了同样的资源,代理服务器不再将请求转发给真实服务器(这是一个耗时的操作),只是从缓存中返回数据。由于客户端和代理服务器在同一个网络中,操作起来会快很多。过滤请求:代理服务器也可用于过滤传入请求。例如,某公司可能会使用代理服务器来阻止其员工访问特定的一组网站,如Xbao、拼多多等。C#中代理设计模式的实现(保护代理):业务需求:请参见下图.正如您在下图中看到的,在右侧我们有一台带有共享文件夹的共享计算机。在左边,我们有员工在软件农场工作。共享计算机包含一个包含机密信息的共享文件夹,只有具有经理和首席执行官角色的员工才能访问此共享文件夹并执行读写操作。另一方面,如果员工是开发人员,则不应允许访问共享文件夹。那就是我们需要做某种保护。这种情况下,保护剂就可以派上用场了。我们在这里可以做的是,在员工和共享计算机之间,我们需要引入一个文件夹代理。这个文件夹代理可以做的是,它会检查员工的角色是经理还是CEO,然后允许员工访问共享文件夹并执行读写操作。另一方面,如果员工角色是Developer那么它会说您没有访问此文件夹的权限。保护逻辑我们可以写在文件夹代理中。现在,我希望您了解代理设计模式。那么,让我们一步步在C#中实现代理设计模式吧。第一步:创建一个Employee类创建一个名为Employee.cs的类文件,并将以下代码复制并粘贴到其中。namespaceProxyDesignPattern{publicclassEmployee{publicstringUsername{get;放;}公共字符串密码{得到;放;}公共字符串角色{得到;放;}publicEmployee(stringusername,stringpassword,stringrole){Username=username;密码=密码;角色=角色;}}}Step2:创建Principal创建一个名为ISharedFolder的接口,然后将以下代码复制并粘贴到其中。该接口定义了RealSubject和Proxy类要实现的通用方法。使用系统;命名空间ProxyDesignPattern{公共接口ISharedFolder{voidPerformRWOperations();}}第3步:创建真实对象创建一个名为SharedFolder.cs的类文件,并将以下代码复制并粘贴到其中。此类实现Principal(ISharedFolder)接口。使用系统;命名空间ProxyDesignPattern{publicclassSharedFolder:ISharedFolder{publicvoidPerformRWOperations(){Console.WriteLine("对共享文件夹执行读写操作");}}}第4步:创建代理对象创建一个命名的SharedFolderProxy。cs并将以下代码复制并粘贴到其中。此类还实现了Subject(ISharedFolder)接口,并且它还持有对真实对象的引用。使用系统;命名空间ProxyDesignPattern{类SharedFolderProxy:ISharedFolder{私人ISharedFolder文件夹;私人雇员;公共SharedFolderProxy(员工emp){employee=emp;}publicvoidPerformRWOperations(){if(employee.Role.ToUpper()=="CEO"||employee.Role.ToUpper()=="MANAGER"){folder=newSharedFolder();Console.WriteLine("共享文件夹代理调用RealFolder'PerformRWOperations方法'");文件夹.PerformRWOperations();}else{Console.WriteLine("共享文件夹代理说'你没有权限访问这个文件夹'");}}}}Step5:客户端代码请修改Main方法,如下所示。使用系统;命名空间ProxyDesignPattern{classProgram{staticvoidMain(string[]args){Console.WriteLine("ClientpassingemployeewithRoleDevelopertofolderproxy");Employeeemp1=newEmployee("Anurag","Anurag123","Developer");SharedFolderProxyfolderProxy1=newSharedFolderProxy(emp1);folderProxy1.PerformRWOperations();控制台.WriteLine();Console.WriteLine("Client将具有RoleManager的员工传递给folderproxy");Employeeemp2=newEmployee("Pranaya","Pranaya123","Manager");SharedFolderProxyfolderProxy2=newSharedFolderProxy(emp2);folderProxy2.PerformRWOperations();控制台.Read();图,请看下图。如上图所示,代理设计模式涉及三个参与者。它们如下:Subject(ISharedFolder):这是一个定义成员的接口,这些成员将由RealSubject和Proxy类实现,以便可以在任何需要RealSubject的地方使用Proxy。在我们的示例中,它是ISharedFolder接口。真实对象(SharedFolder):这是一个类,我们希望通过使用代理类来更高效地使用它。在我们的示例中,它是SharedFolder类。Proxy(SharedFolderProxy):这是一个持有对RealSubject类的引用的类,可以根据需要访问RealSubjectr类成员。它必须实现与RealSubject相同的接口,以便两者可以互换使用。在我们的示例中,它是SharedFolderProxy类。何时在C#实时应用程序中使用代理设计模式?以下是您可以在C#实时应用程序中使用代理设计模式的一些实时场景。添加对现有对象的安全访问。代理将确定客户端是否可以访问感兴趣的对象。简化复杂对象的API。代理可以提供一个简单的API,这样客户端代码就不必处理感兴趣对象的复杂性。为远程资源(如Web服务或REST资源)提供接口。通过要求远程资源在访问资源之前尽快开始操作来协调对远程资源的昂贵操作。在不更改现有类代码的情况下向现有类添加线程安全功能。C#中的代理设计模式实时示例-虚拟代理虚拟代理是创建成本高昂的对象的占位符。真实对象仅在客户端第一次请求或访问对象时创建。让我们通过一个活生生的例子来理解这一点。请看下图。在右侧,您可以看到系统A,它有一个200MB的图像(老虎图像)。在左边你可以看到客户端。在客户端和系统A之间,有系统B充当虚拟代理。假设客户端第一次向系统B(虚拟代理)发送请求以显示老虎图像。虚拟代理(即系统B)所做的是,首先检查虚拟代理中是否存在真实图像对象。如果真实图像对象不存在,则在第1步中创建真实图像对象并从磁盘加载图像,在第2步中调用真实图像对象的显示图像方法。虚拟代理还保存在步骤1中创建的真实图像对象。步骤1,创建真实图像对象并从磁盘加载图像是一项昂贵的操作。假设客户端第二次向虚拟代理发出相同的请求以显示老虎图像。现在,虚拟代理所做的是,检查真实图像对象的存在,它看到虚拟代理中有一个真实图像对象(这是因为在第一个请求中,虚拟代理持有真实图像-图像对象)。因此,虚拟代理所做的是,它不执行第1步,即它不创建真实图像对象并从磁盘加载图像。相反,它将使用现有的真实图像对象并调用DisplayImage方法,即step2。所以,通过这种方式,使用代理设计模式,我们可以避免一次又一次地创建一个昂贵的对象。类图:请看下图:C#中代理设计模式实时实例的实现:让我们使用代理设计模式一步步实现上面的实时实例。众所周知,代理设计模式涉及主体、真实客体和代理客体三个组成部分。让我们一一实现上述组件。第1步:创建正文这将是一个界面。因此,创建一个名为IImage的接口,并将以下代码复制并粘贴到其中。该接口提供由真实对象和代理对象具体类实现的功能。在我们的示例中,该接口定义了一个方法DisplayImagenamespaceProxyDesignPattern{publicinterfaceIImage{voidDisplayImage();}}第二步:创建真正的对象这将是一个具体的类,这个类实现了IImage接口并提供了DisplayImage方法的实现。因此,创建一个名为RealImage.cs的类文件,并将以下代码复制并粘贴到其中。RealImage类的这个构造函数将文件名作为参数,然后从磁盘加载文件。使用系统;命名空间ProxyDesignPattern{publicclassRealImage:IImage{privatestringFilename{get;放;}publicRealImage(stringfilename){文件名=文件名;LoadImageFromDisk();}publicvoidLoadImageFromDisk(){Console.WriteLine("加载图像:"+文件名);}publicvoidDisplayImage(){Console.WriteLine("显示图像:"+文件名);}}}注意:这里的对象创建过程中有一个昂贵的操作。这是因为创建对象时,它会从磁盘加载图像。LoadImageFromDisk方法用于从磁盘加载图像。DisplayImage方法仅用于显示图像。第三步:创建代理这将是一个具体类,它也实现了IImage接口并提供了DisplayImage方法的实现。因此,创建一个名为ProxyObject.cs的类文件,并将以下代码复制并粘贴到其中。作为DisplayImage方法的一部分,首先,我们检查realImage实例是否为空。如果它为null,我们将创建该实例,然后在realImage实例上调用DisplayImage方法。另一方面,如果realImage实例不为null,则不会创建它,而是使用现有的realImage实例来调用DisplayImage方法。namespaceProxyDesignPattern{publicclassProxyImage:IImage{privateRealImagerealImage=null;私有字符串文件名{get;放;}publicProxyImage(stringfilename){文件名=文件名;}publicvoidDisplayImage(){if(realImage==null){realImage=newRealImage(文件名);}realImage.DisplayImage();}}}第四步:客户端请修改Main方法,如下所示。首先,我们创建一个ProxyImage对象来显示老虎图像,然后调用DisplayImage方法3次。在这种情况下,第一次调用DisplayImage方法将创建RealImage实例,因此它将从磁盘加载图像。但是从第二次调用DisplayImage方法开始,它将使用现有的RealImage实例,因此不会从磁盘加载图像。第二次创建代理对象显示狮子图像的过程相同。使用系统;命名空间ProxyDesignPattern{classProgram{staticvoidMain(string[]args){IImageImage1=newProxyImage("TigerImage");Console.WriteLine("Image1第一次调用DisplayImage:");Image1.DisplayImage();//加载必要的Console.WriteLine("Image1callingDisplayImagesecondtime:");Image1.DisplayImage();//加载不必要的Console.WriteLine("Image1第三次调用DisplayImage:");Image1.DisplayImage();//加载不必要的Console.WriteLine();IImageImage2=newProxyImage("狮子图像");Console.WriteLine("Image2第一次调用DisplayImage:");Image2.DisplayImage();//加载必要的Console.WriteLine("Image2第二次调用DisplayImage:");Image2.DisplayImage();//加载不必要的Console.ReadKey();}}}
