(转)代理模式(Proxy)

原文地址:http://www.cnblogs.com/QinBaoBei/archive/2010/05/18/1737866.html

 

为了深刻点理解代理模式,我们先来看一个 Demo ,

首先这个 Demo 是用来测试 QQ 号码是否在线,

这里涉及到的内容是 Web 服务的使用,

这个 Web 服务所在地址为:

http://webservice.webxml.com.cn/webservices/qqOnlineWebService.asmx

如果有不懂 Web 服务的,还可以查看笔者一篇涉及 Web 服务的文章,

http://www.cnblogs.com/QinBaoBei/archive/2010/03/30/1700898.html

然后,我便将上面的验证 QQ 是否在线的这个 Web 服务引入到我的项目中,

并且给这个 Web 服务命名为 WebService.TestQQ

image

然后就是来编写类了,

主要是一个 TestResult 类,这个类的作用就是来完成访问 Web 服务,返回验证结果,

其具体代码如下:

namespace ProxyQQ
{
    public static class TestResult
    {
        public static string GetResult(string qqNum)
        {
          
//调用引用的 Web 服务(自命名为 WebService.TestQQ)
            WebService.TestQQ.qqOnlineWebService testQQ =
                new WebService.TestQQ.qqOnlineWebService();

            return testQQ.qqCheckOnline(qqNum);
        }
    }
}

然后就是要编写客户端了,我这里使用的是一个 WinForm 应用程序来实现的,

image

这个项目中唯一一个窗体 TestQQ 的代码如下

using System;
using System.Windows.Forms;

namespace ProxyQQTest
{
    public partial class TestQQ : Form
    {
        public TestQQ()
        {
            InitializeComponent();
        }

        private void btnQuery_Click(object sender, EventArgs e)
        {
    
       //调用 ProxyQQ 命名空间下的静态类 TestResult 的
            //静态方法 GetResult()来判断 QQ 状态

            string result =
                ProxyQQ.TestResult.GetResult(txtQQNum.Text.Trim());

            string msg = String.Empty;
            switch (result)
            {
                case "Y":
                    msg = "该 QQ 在线";
                    break;
                case "N":
                    msg = "该 QQ 离线";
                    break;
                case "E":
                    msg = "该 QQ 号码不存在";
                    break;
                case "A":
                    msg = "商业用户验证失败";
                    break;
                case "V":
                    msg = "免费用户超过数量";
                    break;
                default:
                    break;
            }
            MessageBox.Show(msg, "提示",
                MessageBoxButtons.OK,
                MessageBoxIcon.Information);
        }
    }
}

下面就来查询一下 QQ 号码咯

image

然后我让我的 QQ 上线再来查看

image

好,说了这么多了,感觉是在介绍 Web 服务似的,

但是请不要误会,本篇博文是来介绍代理模式的,而非 Web 服务,

下面我们就从上面的这个 Demo 来谈谈代理模式,

其实上面谈到的 Demo 就是代理模式的一种最典型的应用--远程代理,

先来看上面的 Demo 中,我添加的那个 Web 服务,

当我在我的项目中添加了 Web 服务后呢,

大家可以看到会在项目中自动生成一个 WebReference 的文件夹以及一些文件,

其实这些就是代理了,

image

您看我在应用程序中只是使用了下面一丁点代码,

  //调用引用的 Web 服务(自命名为 WebService.TestQQ)
   WebService.TestQQ.qqOnlineWebService testQQ = 
       new WebService.TestQQ.qqOnlineWebService();

   return testQQ.qqCheckOnline(qqNum);

我们在客户端只需要通过这一丁点代码就可以完成访问 Web 服务并且返回结果,

也可以说成是客户端通过调用代理来完成远程访问并返回结果。

         

下面就来看看什么是远程代理?

远程代理可以看做另一个服务器上的对象在本地服务器上的代表,

调用代理的方法就会被代理通过网络来转发到远程执行,并且结果会通过网络返回给代理,

然后再由代理将结果转发给客户。

其实上面对远程代理的定义还是不明确的,就拿 Web 服务来说的话,您也可以调用你自己的项目中的 Web 服务的,

所以完整的远程代理的定义是,为一个不同地址空间中的对象提供一个局部代表对象,

不过这个不同的地址空间呢可以在您的本地机也可以在远程机器上,

所以在上面的 Demo 中,

就可以把 WebService.TestQQ.qqOnlineWebService (代理对象)看做是

验证 QQ 号码这个对象(这里看做一个对象,它是被代理的对象)在本地机器(也就是我的项目中)上的代理对象,

而后,我在客户端中便只需要对这个代理对象进行访问和操作就 OK 了,其他的内容就交给代理对象来完成了,

这是典型的代理模式。

上面呢,介绍的只是代理模式的一种最典型的应用,也就是远程代理,而下面就要来介绍代理模式的一些具体内容了,

        

          

什么是代理模式?

代理模式为另一个对象提供一种代理(换句话说就是替身)以控制对这个对象的访问,使用代理模式创建代理对象,

让这个代理对象控制某个对象的访问。

下面就来看看代理模式的结构类图

image

从上面的结构类图可以看出,代理类和具体主题类都继承子抽象主题类,

何为要这样实现继承呢?

很简单的,由于 Proxy 和 RealSubject 均继承自 Subject 这个抽象主题类,

并且在 Proxy 和 RealSubject 中均实现了 Request 方法,

所以在需要使用 RealSubject 的地方便可以使用 Proxy 来替代

(换句话说的话,可以认为 Proxy 和 RealSubject 是同一类型)

由于使用了 Proxy 来替代 RealSubject ,所以便实现了通过 Proxy 来代理 RealSubject ,

同时在 Proxy 这个代理类中保存和维护了一个 RealSubject 对象,

当然就在一定程度上实现了通过 Proxy 来控制 RealSubject 。

       

          

下面还是先来看看这个代理模式的最基本的结构实现吧

Subject 类

namespace Proxy
{
    public abstract class Subject
    {
        public abstract void Request();
    }
}

Proxy 类

using System;

namespace Proxy
{
    public class Proxy:Subject
    {
        private RealSubject realSubject;

        public override void Request()
        {
            Console.WriteLine(this.GetType().ToString());

            if (realSubject == null)
            {
                realSubject = new RealSubject();
            }
            realSubject.Request();
        }
    }
}

RealSubject 类

using System;

namespace Proxy
{
    public class
RealSubject:Subject
    {
        public override void Request()
        {
            Console.WriteLine(this.GetType().ToString());
        }
    }
}

客户端代码

using System;

namespace ProxyTest
{
    class Program
    {
        static void Main(string[] args)
        {
           Proxy.Subject proxy = new Proxy.Proxy();
            proxy.Request();

            Console.ReadKey();
        }
    }
}

image

光看上面的代码和效果,我想大家很难明白是怎么一回事,那么还请看下面的解释,然后再回过头结合代码来看,

那么大家应该就可以明白代理模式到底是咋一回事了,

首先,可以看到 Proxy 和 RealSubject 这两个类都继承自抽象类 Subject ,

同时均实现了在抽象类 Subject 类中定义的 Request 方法,

这样的话,在某一层意义上来说,Proxy 就是 RealSubject 的替身了,

因为他们的抽象类型都是一样的,所以,便可以在 RealSubject 出现的地方使用 Proxy 来替代了,

比如在上面的例子中,我本来的意义是要在客户端中调用 RealSubject 的 Request 方法的,

所以本来在客户端代码中应该如下写的:

     Proxy.Subject realSubject= new Proxy.RealSubject();
   realSubject.Request();

而事实上并非这样,我是通过实例化一个 Proxy 类来完成操作的,因为我在 Proxy 中保存了一个 RealSubject 对象,

并且在 Proxy 类的 Request 方法中调用了 RealSubject 的 Request 方法,

所以便是代理实现了调用 RealSubject 的 Request 方法,

在这里,我想就有疑问了,那就是我为什么一定要在客户端来通过 Proxy 代理完成这个操作,

而不是直接实例化 RealSubject 对象来完成 Request 操作了,

其实,这里涉及到的便是代理模式的具体应用了,前面看了一种应用也就是远程代理,

下面我们来看另外一种代理模式的应用,也就是虚拟代理,

比如,我要加载一个很大的视频文件或者是图片文件(比如 800 像素拍下的照片 2M),

此时由于网络速度慢的缘故,在加载的时候费个什么几秒钟那是非常常见的,但是就是在这几秒钟中,

难道您就让用户干巴巴的等着吗?要我是用户的话,看着半天没反应的浏览器或者是窗体,

我想,我还是关闭算了吧 ! ! !

那么我们有什么办法来解决上面的问题呢?

其实有一种比较好的办法,就是当图片在下载时,可以发布一个提示消息,比如“正在下载中,请等待”,

做的好一点的话,还可以显示一张本地的小图片,这样会更炫,

然后等下载完成后便将这些提示消息去掉,然后显示图片就 OK 了,这样可以极大的提高用户体验,

其实这种效果在很多地方都常见了,而这就是通过虚拟代理来解决的,

我们先来看一下腾讯主页上这种效果吧

image

        

           

下面就来看如何通过虚拟代理来完成上面的这种效果

我们就来看类了,

首先是 Subject 这个抽象类,在这里是 LoadImage 来充当

namespace ProxyVirtual
{
    public abstract class
LoadImage
    {
        public abstract void LoadImageRequest();
    }
}

然后是 Proxy 这个代理类,这里由 ProxyLoadImage 来充当,

using System.Windows.Forms;
using System.Drawing;
using System.Threading;

namespace ProxyVirtual
{
    public class
ProxyLoadImage : LoadImage
    {
 
      //这里要保存一个具体主题类的引用
        //这样才能够实现控制具体主题了 RealLoadImage

        private RealLoadImage realLoadImage;

        private PictureBox pcBox;

        public ProxyLoadImage(PictureBox pcBox, RealLoadImage realLoadImage)
        {
            this.pcBox = pcBox;
            this.realLoadImage = realLoadImage;
        }

        public override void LoadImageRequest()
        {
            //首先是要实例化一个线程
            Thread thread = new Thread(ThreadMethod);
            //然后就是要启动这个线程了
           
thread.Start();
        }

        private void ThreadMethod()
        {
   
        //将整个提示用户还在下载的图片(小图片)
            //和正在下载的图片(大图片)放在同一个线程中
            //可以防止其他线程对整个应用程序进行干扰

            pcBox.Image = Image.FromFile("SquareCircle.gif");
            realLoadImage.LoadImageRequest();
        }
    }
}

还有一个就是具体主题类 RealLoadImage 类了

using System.Windows.Forms;
using System.Drawing;
using System.Net;

namespace ProxyVirtual
{
    public class RealLoadImage : LoadImage
    {
        private string strUrl;
        private PictureBox pcBox;

        public RealLoadImage(string strUrl, PictureBox pcBox)
        {
            this.strUrl = strUrl;
            this.pcBox = pcBox;
        }

        public override void LoadImageRequest()
        {
           
//发出对指定 URL 路径的请求(这里是请求一张图片)
           
WebRequest request = WebRequest.Create(strUrl);
            //返回对请求的响应结果
           WebResponse response = request.GetResponse();
            //从网络资源中返回数据流,然后给图片框显示
            pcBox.Image = Image.FromStream(response.GetResponseStream());
        }
    }
}

然后就是客户端代码了(这里是一个 Form 的 Code-Behind)

using System;
using System.Windows.Forms;

namespace ProxyVirtualTest
{
    public partial class
Test : Form
    {
        public Test()
        {
            InitializeComponent();
        }

        private void Test_Load(object sender, EventArgs e)
        {
            ProxyVirtual.LoadImage loadImage =
               
new ProxyVirtual.ProxyLoadImage(this.pcBox,
                    new ProxyVirtual.RealLoadImage(
                        "
http://images.cnblogs.com/cnblogs_com/qinbaobei/6.jpg",
                        this.pcBox));

            //调用代理类的 LoadImageRequest
            loadImage.LoadImageRequest();
        }
    }
}

下面也把效果给出来,刚开始加载的时候效果是

image

当下载完成以后,便会出现

image

上面的这张图片呢,是我的博客中的一张图片,我通过 URL 来下载到我的应用程序当中。

下面我再给出上面这个 Demo 的类图,大家可以拿这个类图和最开始的代理模式的结构类图比较比较,

image

我们不谈别的内容,光从上面的这幅类图中便可以看出上面的 Demo 使用的就是代理模式,

        

        

下面我们还再来具体的谈一下何为虚拟代理?

虚拟代理是作为创建大的对象的代理类,一般来说,创建一个对象需要消耗比较大的资源时,

可以通过虚拟代理来实现这个对象只有在需要的时候才会被真正创建,

可以通过使用代理(这个代理不怎么耗资源)来在必要的时候将被代理的对象加载,

也就是通过不怎么耗资源的代理来控制什么时候需要加载比较耗资源的被代理对象,

在上面的 Demo 中,大的图片就是比较耗资源的,所以通过一个不怎么耗资源的小图片先来代理它,

在真正需要这个大图片的时候再通过代理来加载。

再看一个虚拟代理的应用,那就是当您打开一个有很多图片的网页时,

一般来说,文字是全部可以看到的(会在加载网页的时候全部下载过来),

而图片却必须要一张一张的下载才能看得

(比如您将滑轮往下滚会看到一些图片并没有显示出来,只是在那里留出一个方框,

   而真实的图片就需要等待才能显示),

那些未打开的图片框就是通过虚拟代理来替代了真实的图片,

此时,代理存储了真实图片的路径和大小,所以在也没上才会出现图片的方框,而并没有真实的图像。

在上面浏览器中使用代理模式的好处是什么呢?很明显,通过使用虚拟代理优化了下载。

              

                  

上面呢,重点介绍了代理模式的两种应用,即远程代理和虚拟代理,其实呢,代理模式还有很多变种的

既然是变种的话,基本上就差不太多远啦,

比如安全代理,智能引用代理,缓存代理,写入时复制代理,防火墙代理等等,

在这里就不做一一介绍了,如果有想了解的,可以 Google 或者是 Bing 一下,就会出来一大堆了 ! ! !            

还有就是 TerryLee 的博客上也有一点点介绍的,感兴趣的可以去看看 ! ! !

 

转载于:https://www.cnblogs.com/fcsh820/archive/2010/05/18/1738088.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/423156.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++深度剖析教程31】被遗弃的多重继承

加qq1126137994 微信:liu1126137994 C中是否允许一个类继承多个父类? C支持编写多重继承的代码: 一个子类可以拥有多个父类子类拥有所有父类的成员变量子类继承父类所有的成员函数子类对象可以当做任意父类对象使用 多重继承的语法规则&a…

zookeeper思维导图

之前用word文档记笔记,但是没有思维导图清晰,又整理了一下,分享一下;

管理软件本质论

我们上管理软件到底是为了什么?1 为员工提供自动化工具,可以让他们节省出更多的时间可以做更多的工作?2 可以通过管理软件的互联网联网特性或局域网联网特性,让部门和部门之间、总部和分公司之间按业务流程通常运营?2 …

【C++深度剖析教程32】new/malloc区别 delete/free区别

加qq1126137994 微信:liu1126137994 一起学习更多技术!!! 1、new与malloc的区别: new是关键字,它是C语言的一部分,而malloc是由C库提供的函数new分配的内存的单位是具体的类型大小&#xff0c…

redis 思维导图

之前整理的redis 思维导图,分享一下,后续持续更新;

软件汉化教程

看到网上经常有人问汉化方面的东西,我今天也来灌水一篇,来个汉化扫盲教程。写的不好的地方欢迎大家指正!OK,现在我们进入正题。我这里所说的汉化,是指汉化 Windows 下的 PE 文件,把其他语言界面的程序翻译为…

图的DFS深度遍历

最近复习了一下图的内容,记录一下,后续添加详解(无向图的深度遍历) package com.qey.learn;import java.util.ArrayList; import java.util.Arrays;/*** ClassName graph* Description* Author qianxl* Date 2021-03-06 17:18* V…

【C++深度剖析教程33】C++中的构造函数与析构函数是否可以为虚函数

加qq1126137994 微信:liu1126137994 一起学习更多技术!!! 问题一:构造函数与析构函数可以成为虚函数么? 答案: 1、构造函数不可以成为虚函数 因为在构造函数执行结束后,虚函数表…

网站切图初学

先做一个简单的说明为什么选择Photoshop软件而没有选择Firework软件。Friework Dreamweaver Flash号称网页制作三剑客,Friework与Dreamwaver整合得更为紧密,在这里只所以选择photoshop只是因为我的偏好,况且我对 firework软件使用的次数很少&…

【C++深度剖析教程34】C++中的强制类型转换dynamic_cast

加qq1126137994 微信:liu1126137994 一起学习更多技术!!! C中的继承中,如何使用强制类型转换? 知识点: dynamic_cast是与继承相关的类型转换关键字dynamic_cast要求相关的类中必须有虚函数dy…

main函数的参数的含义

转载自:点击链接 链接2 加qq1126137994 微信:liu1126137994 一起学习更多技术!!! 最近学习服务器网络编程,遇到了一个问题,main函数的参数,特意整理资料记录之!&#…

C#FTP操作

C# FTP操作类 收藏 using System;using System.Collections;using System.IO;using System.Net;using System.Net.Sockets;using System.Text;using System.Text.RegularExpressions; namespace Discuz.Common{ /// <summary> /// FTP类 /// </summary> …

【C++深度剖析教程35】函数模板的概念和意义

加qq1126137994 微信&#xff1a;liu1126137994 一起学习更多技术&#xff01;&#xff01;&#xff01; 1、问题引入&#xff1a; C中有几种变量交换的方法&#xff1f; 定义宏代码块和定义函数 #include <iostream> #include <string>using namespace std;#d…

生产者和消费者

注意&#xff01;&#xff01; notify和wait 使用后续补充 package com.qey.learn;/*** ClassName Water* Description* Author qianxl* Date 2021-03-01 23:09* Version 1.1**/ public class Water {// 服务员来提供产品的输入的输出private int product;public Water(int m…

前端学习(133):雪碧图实现原理

百度词条对雪碧图的解释是&#xff1a;CSS雪碧 即CSS Sprite&#xff0c;也有人叫它CSS精灵&#xff0c;是一种CSS图像合并技术&#xff0c;该方法是将小图标和背景图像合并到一张图片上&#xff0c;然后利用css的背景定位来显示需要显示的图片部分。 举个应用的实例&#xff…

如何在C++中动态分配二维数组

一般是三种方法&#xff1a;(1)用vector的vector&#xff0c;(2)先分配一个指针 数组&#xff0c;然后让里面每一个指针再指向一个数组&#xff0c;这个做法的好处是访问数组元素时比较直观&#xff0c;可以用a[x][y]这样的写法&#xff0c;缺点是它相当于C#中的一个锯齿 数组&…

循环打印ABA问题

注意&#xff01;&#xff01; notify 虚拟锁问题&#xff0c;后续补充 package com.qey.learn;/*** ClassName SwapPrint* Description* Author qianxl* Date 2021-03-02 14:46* Version 1.1**/ public class SwapPrint {public int flag 0;public synchronized void prin…

【C++深度剖析教程36】深入理解函数模板

加qq1126137994 微信&#xff1a;liu1126137994 一起学习更多技术&#xff01;&#xff01;&#xff01; 1、函数模板深入理解 编译器从函数模板通过具体类型产生不同的函数编译器会对函数模板进行两次编译 *对模板进行编译 *对参数替换后的函数进行编译 注意事项&#xf…

【C++深度剖析教程37】类模板的概念和意义

加qq1126137994 微信&#xff1a;liu1126137994 一起学习更多技术&#xff01;&#xff01;&#xff01; 1、类模板 一些类主要用于存储和组织数据元素类中数据的组织方式和数据元素的具体类型无关如 数组类&#xff0c;链表类&#xff0c;stack类&#xff0c;queue类等 C中…