设计模式(十三):从“FQ”中来认识代理模式(Proxy Pattern)
我们知道Google早就被墙了,所以FQ才能访问Google呢,这个“FQ”的过程就是一个代理的过程。“代理模式”在之前的博客中不止一次的提及过,之前的委托回调就是代理模式的具体应用。今天我们就从“FQ”中来认识一下代理模式。代理模式的定义如下:
代理模式:为另一个对象提供一个替身或占位符以控制对这个对象的访问。
首先说一下什么是“代理”吧,其实代理很好理解,你就把“代理”看成是二道贩子,说的好听点叫代理商。就是你买个东西,不从生产地直接买,而是通过二道贩子,三道贩子来进行购买,这些商贩就是代理商,也就是我们今天所说的代理。说的具体点,比如你要买棵萝卜,那么一般人不会去找菜农,然后给他们钱直接去地里薅萝卜。大部分人是通过商超来获取萝卜,这些商超就是所谓的萝卜代理商,也就是二道贩子。
那么在说一下什么是“FQ”吧,今天就拿Facebook为例。你是用户,Facebook网站就好比大萝卜,你直接去拔萝卜(直接访问FaceBook站点)不太现实,所以你得通过二道贩子(各种网络代理)来获取你想要的萝卜呢。可是你默认的代理商(GFW--长城防火墙)发现你购买萝卜不太单纯,所以就拒绝进行供货,这就是你访问的网站被墙了。可是你不甘心呢,家里兔子还等着吃萝卜呢。你得寻找新的代理商,此刻你就找到了Shadowsocks这个二道贩子。Shadowsocks没有什么估计的,他可以给你提供大萝卜,这就是FQ。Shadowsocks如何使用在此就不做过多的赘述了,自行Google。
言归正传,上面说这么多无非都是在解释什么是“代理”。今天我们就使用Swift代码来模拟上述的“FQ”过程,通过这个FQ过程来认识一下“保护代理模式”和“远程代理模式”,然后在结合着另一个实例来认识一下“虚拟代理模式”。进入今天的主题。
一、“FQ”的类图设计
其实在“FQ”这件事情上我们不关心如何去FQ,而是关心如何使用代理。在真正网络访问时,无论你是进行FQ访问,还是不FQ访问,都使用的“代理模式”。只不过FQ之前使用的是“保护代理模式”(GFW), 而FQ之后使用的是“远程代理模式”(因为今天的主题是“代理模式”,关于FQ我们先这么理解着,真正的网络代理要比这个复杂的多)。在该部分,基于我们今天这个FQ的场景,然后使用“代理模式”来设计GFW和Shadowsocks两种代理方式。下方就是我们所设计的FQ的类图,稍后会给出具体的代码实现。
在下方类图中绿框的部分是我们要访问的网站,其中有被墙的Facebook和Twitter,也有没被墙的Cnblogs。这三个Web站点都遵循一样的网络访问协议,此处我们定义了InternetAccessProtocol协议(接口)来模拟这些Web站点所遵循的网络协议。在InternetAccessProtocol网络访问协议中的response()方法是用来响应用户网络请求的,getId()方法用来返回该网站的唯一标示,也就是网站的域名。所有的Web站点都必须遵循该网络请求协议。
上面红框中是我们今天的核心部分,也就是网络代理部分。该部分声明了一个协议ProxyType,所有网络代理也都必须遵循该协议。因为网络代理是用来代理网络访问的,它作为用户与Web站点的中转者,对于用户来说该代理就如同真正的网站一样,随意ProxyType协议也必须的遵循上面定义的网络访问协议InternetAccessProtocol。在红框中有两个网络访问的代理,一个是ShadowsocksProxy,一个是GreatFirewall。
ShadowsocksProxy是远程代理,你在使用该远程代理时,你访问的网站不受限制,也就是说你可以访问Google、Twitter、Facebook这些网站,远程代理的态度是Open&Freedom的。远程代理只负责桥接,至于你访问的什么网站它不做关心,它只负责响应你的请求。而下方的GreatFirewall就不同了,GreatFirewall是一个保护代理,其中有一个blackList(黑名单),如下所示。blackList数组中记录的就是那些被墙的网站,只要是请求的网站在blackList中,你的请求是不会得到你请求网站的响应的。这也就是保护代理模式的功能,保护代理模式会添加一些权限的限制,会限制用户访问一些不安全的网站。
然后就是黄框中的Client了,在Client中依赖的是代理接口,也就是说Client只能依赖于代理进行网络访问。默认的代理就是GreatFirewall,GreatFirewall会屏蔽一些不能让你访问的网站。如果用户选择ShadowsocksProxy远程代理进行网络访问,就不受GreatFirewall的限制了,这也就是所谓的FQ。在下方Client类中就有两种上网方式,一种是Shadowsocks一种是GreatFireFirewall。有一点还是需要说明的是,真正的FQ不是不经过GreatFirewall,而是你的代理地址在GreatFirewall的白名单中,就是你可以通过GreatFirewall来访问的你的代理,然后你的代理是不经过GreatFirewall来访问你想要访问的Web站点的。该实例只是我们了解代理模式来模拟出来的实例,我们的重点在代理模式。

二、代码实现
上述给出了结构的设计,接下来我们就需要进行具体的代码实现了,我们在实现时仍然使用Swift语言。有了上面的类图设计,然后在给出代码实现似乎简单了许多。下方会分部分给出上述类图的代码实现,下方是一些代码的截图,更完整的实例请参见本博客后方github分享地址。
1.网络访问协议与Web站点的实现
下方就是网络访问协议与Web站点的具体实现。在InternetAccessProtocol网络访问协议中的response()方法用来响应用户的请求,getId()方法用来返回网站的域名。在InternetAccessProtocol协议的下方分别实现了三个web站点:Facebook、Twitter、Cnblogs。众所周知,前两个已经被墙了,所以如果你要想访问的话,你得FQ呢。web站点以及网络访问协议代码如下:

2. 两种代理的实现
首先我们先实现一个比较简单的,也就是远程代理。使用远程代理访问Web站点时没有一些不必要的限制,就是你访问什么网站,该远程代理就会请求什么网站并返回相应的信息。下方代码片段就是代理协议和远程代理ShadowsocksProxy的具体实现。在ProxyType代理协议中,setDelegate(delegate)方法用来设置代理,也就是用来设置访问的Web站点,ProxyType协议也同样遵循InternetAccessProtocol协议。在ShadowsocksProxy中的delegate成员变量就是用户要请求的Web站点,你访问的是A站点,那么此处的代理就是A站点的对象。在ShadowsocksProxy中的response()方法会请求delegate的response()方法,而代理中的getId()方法中则会返回当前远程代理的域名或者IP, 这一点很关键呢。具体代码实现如下:

接下来我们来实现我们的长城防火墙,也就是GreatFirewall。下方的代码实现就是GreatFirewall的实现,其中比上述的远程代理的实现多了一些东西,其中多了一项权限的控制。当你使用GreatFirewall来访问Web站点时,GreatFirewall首先会判断你所访问的Web站点在不在自己的黑名单中,也就是下方的blackList。如果你访问的Web站点在blackList中,就说明该站点被墙了,GreatFirewall就不会调用该Web站点的response(),所以用户就不会受到该网站的相应。相反,如果不在黑名单中,那么就会设置代理,然后就可以调用该Web站点的response()方法做出相应的响应,这也就是所说的“保护代理模式”。其实说白了,保护代理模式就是在远程代理上添加了一些权限的控制。具体代码实现如下。

三、Client与测试用例
上面实现完了Web站点,与Web站点的两个访问代理,下方我们就该实现Client用户的代码。然后在此基础上给出测试用例。下方的代码段就是我们的Client的代码实现。在Client中你可选择shadowsocks也可以选择使用greatFirewall。Client代码如下:

下方是我们的测试用例,以及该测试用例的输出结果。我们先使用远程代理访问Facebook是可以访问的,因为我们的远程代理没有添加任何限制。如果你通过GFW来访问Facebook,就访问不了,因为Facebook在GFW的黑名单中。但是你通过GFW访问远程代理服务器,然后在通过远程代理服务器去访问FaceBook是可行的。因为我们的远程代理服务器不在GFW的黑名单中,所以我们可以访问远程代理服务器,而我们的远程代理服务器是可以访问Facebook,所以我们可以访问Facebook。这也是测试用例中的第三段。代码以及输出结果如下所示。

四、虚拟代理
虚拟代理的作用就是为占用存储空间比较大的对象提供替身。当我们实例化大对象需要一定时间时(比如从网请求较大的图片),我们就可以使用虚拟代理提供一个对象的替身,等对象加载完毕后在使用我们这个真正的对象。因为虚拟代理较为简单,在此就不给出类图了,就直接给出代码实现吧。其实虚拟代理说白了也是代理模式,就是在大对象的使用者与大对象间添加了一层,这一层就是虚拟代理。
下方我们就以加载大图片为例,当我们加载比较大的图片时,为了不让用户等待,我可以先通过虚拟代理模式添加一个小的图片。然后在虚拟代理中将大图片加载完毕后我们在换回大的图片即可。下方我们创建了一个图片协议ImageType,然后创建了一个大的图片BigImage和一个小的图片SmallImage。SmallImage就作为BigImage未加载时的替身,当SmallImage加载完毕后我们就不使用SmallImage,而使用BigImage。而这一系列的替换的过程交给我们的虚拟代理来处理。
下方代码段中的BigImageProxy就是我们的虚拟代理。BigImageProxy也遵循于ImageType协议,对于用户来说,BigImageProxy的用法与普通的图片是一样的。在BigImageProxy中的loadImage()方法是我们虚拟代理的核心。在调用虚拟代理中的loadImage()方法时,如果BigImage已被实例化,就会调用loadImage()方法,如果BigImage没有实例化,那么就会调用SmallImage中的loadImage()方法,并且对BigImage进行实例化,并将虚拟代理中bigImage的状态设置为正在初始化状态。具体实现代码如下所示:

下方代码段就是上述虚拟代码的测试用例。ImageClient依赖的是ImageType协议,所以其中的image成员变量可以是真正的图片,也可以是我们的虚拟代理。虚拟代理对象的使用方式与普通图片的使用方式一致,测试用例如下所示:

今天我们的博客中就介绍了三种代理模式:远程代理模式、保护代理模式、虚拟代理模式。远程代理访问是控制访问远程对象,保护代理是基于权限的资源访问,虚拟代理是控制访问创建开销大的资源。
上述代码示例仍然会在github上进行分享,分享地址为:https://github.com/lizelu/DesignPatterns-Swift
设计模式(十三):从“FQ”中来认识代理模式(Proxy Pattern)的更多相关文章
- 设计模式系列之代理模式(Proxy Pattern)——对象的间接访问
说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...
- 乐在其中设计模式(C#) - 代理模式(Proxy Pattern)
原文:乐在其中设计模式(C#) - 代理模式(Proxy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 代理模式(Proxy Pattern) 作者:webabcd 介绍 为 ...
- 设计模式 - 代理模式(proxy pattern) 未使用代理模式 具体解释
代理模式(proxy pattern) 未使用代理模式 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 部分代码參考: http://blog.csdn. ...
- 二十四种设计模式:代理模式(Proxy Pattern)
代理模式(Proxy Pattern) 介绍为其他对象提供一个代理以控制对这个对象的访问. 示例有一个Message实体类,某对象对它的操作有Insert()和Get()方法,用一个代理来控制对这个对 ...
- 代理模式(Proxy pattern)
代理模式(proxy pattern):作用:为其他对象提供一种代理,以控制对这个对象的访问.代理对象在客户端对象和目标对象之间起中介的作用. 代理模式涉及到的角色: 抽象角色:声明真实对象和代理对象 ...
- 设计模式——代理模式(Proxy Pattern)
代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问. UML图: 模型设计: Subject类: package com.cnblog.clarck; /** * Subject 类 ...
- 13.代理模式(Proxy Pattern)
using System; namespace Test { //抽象角色:声明真实对象和代理对象的共同接口. //代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象, //同时代理 ...
- c#设计模式之代理模式(Proxy Pattern)
引言 代理这个词语,大家在现实世界已经频繁的接触过,例如火车站代理售票点,因为这些代理售票点的存在,我们不必要去火车站的售票处就可以查询或者取到火车票.代理点本身是没有能力生产车票的,我们在代理处享受 ...
- C#设计模式——代理模式(Proxy Pattern)
一.概述在软件开发中,有些对象由于创建成本高.访问时需要与其它进程交互等原因,直接访问会造成系统速度慢.复杂度增大等问题.这时可以使用代理模式,给系统增加一层间接层,通过间接层访问对象,从而达到隐藏系 ...
随机推荐
- 完美判断iframe是否加载完成
var iframe = document.createElement("iframe"); iframe.style.width = "265px"; ifr ...
- 23种设计模式--观察者模式-Observer Pattern
一.观察者模式的介绍 观察者模式从字面的意思上理解,肯定有两个对象一个是观察者,另外一个是被观察者,观察者模式就是当被观察者发生改变得时候发送通知给观察者,当然这个观察者可以是多个对象,在项 ...
- Expression Blend创建自定义按钮
在 Expression Blend 中,我们可以在美工板上绘制形状.路径和控件,然后修改其外观和行为,从而直观地设计应用程序.Button按钮也是Expression Blend最常用的控件之一,在 ...
- SQLServer 版本之八大方法搞清 "我是谁"
你正在使用 SQL Server 的哪个版本? 贴士:作为一个SQL Server数据库管理者或维护.支持人员,应该会经常问自己这样一个问题:我当前SQL Server版本号是?当前版本已经有的累计更 ...
- NLP点滴——文本相似度
[TOC] 前言 在自然语言处理过程中,经常会涉及到如何度量两个文本之间的相似性,我们都知道文本是一种高维的语义空间,如何对其进行抽象分解,从而能够站在数学角度去量化其相似性.而有了文本之间相似性的度 ...
- 【绝对干货】仿微信QQ设置图形头像裁剪,让你的App从此炫起来~
最近在做毕业设计,想有一个功能和QQ一样可以裁剪头像并设置圆形头像,额,这是设计狮的一种潮流. 而纵观现在主流的APP,只要有用户系统这个功能,这个需求一般都是在(bu)劫(de)难(bu)逃(xue ...
- mongodb
修改所有的记录: > db.t_express_apply.update({},{$set:{"isStatus" : 0}},{multi:true})WriteResul ...
- win10安装blueCFD
blueCFD其实安装起来听简单,不过还是有点问题.最大的问题是该软件没有文档,不过想来也是,人家只是提供一个linux外壳,剩下的工作还是OpenFoam,该干嘛干嘛,也用不着文档.问题在于我们需要 ...
- 使用MonoTouch.Dialog简化iOS界面开发
MonoTouch.Dialog简称MT.D,是Xamarin.iOS的一个RAD工具包.它提供易于使用的声明式API,不需要使用导航控制器.表格等ViewController来定义复杂的应用程序UI ...
- 微软“.Net社区虚拟大会”dotnetConf2015:关键词:.NET 创新、开源、跨平台
去年 11 月的时候,微软开源了 .NET CoreFX,然后是今年 2 月份的 .NET CoreCLR.自那时以来,已经有大约 3500 人在 GitHub 上进行了提交,而且贡献者的人数还在持续 ...