设计模式(十三):从“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)
一.概述在软件开发中,有些对象由于创建成本高.访问时需要与其它进程交互等原因,直接访问会造成系统速度慢.复杂度增大等问题.这时可以使用代理模式,给系统增加一层间接层,通过间接层访问对象,从而达到隐藏系 ...
随机推荐
- 百度推出新技术 MIP,网页加载更快,广告呢?
我们在2016年年初推出了MIP,帮助移动页面加速(原理).内测数据表明,MIP页面在1s内加载完成.现在已经有十多家网站加入MIP项目,有更多的网站正在加入中.在我们收到的反馈中,大部分都提到了广告 ...
- Redis数据库
Redis是k-v型数据库的典范,设计思想及数据结构实现都值得学习. 1.数据类型 value支持五种数据类型:1.字符串(strings)2.字符串列表(lists)3.字符串集合(sets)4.有 ...
- Carousel 旋转画廊特效的疑难杂症
疑难杂症 该画廊特效的特点就是前后元素有层级关系. 我想很多人应该看过或者用过这个插件carousel.js,网上也有相关的教程.不知道这个插件的原型是哪个,有知道的朋友可以告诉我. 该插件相对完美, ...
- 算法与数据结构(十四) 堆排序 (Swift 3.0版)
上篇博客主要讲了冒泡排序.插入排序.希尔排序以及选择排序.本篇博客就来讲一下堆排序(Heap Sort).看到堆排序这个名字我们就应该知道这种排序方式的特点,就是利用堆来讲我们的序列进行排序.&quo ...
- OEL上使用yum install oracle-validated 简化主机配置工作
环境:OEL 5.7 + Oracle 10.2.0.5 RAC 如果你正在用OEL(Oracle Enterprise Linux)系统部署Oracle,那么可以使用yum安装oracle-vali ...
- 一个诡异的COOKIE问题
今天下午,发现本地的测试环境突然跑不动了,thinkphp直接跑到异常页面,按照正常的排错思路,直接看thinkphp的log 有一条 [ error ] [2]setcookie() expects ...
- MyBatis源码分析(二)语句处理器
StatementHandler 语句处理器,主要负责语句的创建.参数的设置.语句的执行.不负责结果集的处理. Statement prepare(Connection connection, Int ...
- 关于SMARTFORMS文本编辑器出错
最近在做ISH的一个打印功能,SMARTFORM的需求本身很简单,但做起来则一波三折. 使用环境是这样的:Windows 7 64bit + SAP GUI 740 Patch 5 + MS Offi ...
- ABAP单元测试最佳实践
本文包含了我在开发项目中经历过的实用的ABAP单元测试指导方针.我把它们安排成为问答的风格,欢迎任何人添加更多的Q&A's,以完成这个列表. 在我的项目中,只使用传统的ABAP report. ...
- Conversion to Dalvik format failed: Unable to execute dex: Multiple dex files define ...
Conversion to Dalvik format failed: Unable to execute dex: Multiple dex files define ... 这个错误是因为有两个相 ...