設計模式(十三):從“FQ”中來認識代理模式(Proxy Pattern)

来源:http://www.cnblogs.com/ludashi/archive/2016/05/16/5454189.html
-Advertisement-
Play Games

前段時間因為“某度競價排名”的事情鬧得沸沸揚揚的,因為某度搜出來的內容的質量實在是不敢恭維,所以早就戒掉了某度改用Google了。但是Google早就被牆了呢,所以翻牆才能訪問Google呢,這個“翻牆”的過程就是一個代理的過程。“代理模式”在之前的博客中不止一次的提及過,之前的委托回調就是代理模式 ...


前段時間因為“某度競價排名”的事情鬧得沸沸揚揚的,因為某度搜出來的內容的質量實在是不敢恭維,所以早就戒掉了某度改用Google了。但是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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 在一些較為複雜的業務中,客戶端需要依據條件,執行相應的行為或演算法。在實現這些業務時,我們可能會使用較多的分支語句(switch case或if else語句)。使用分支語句,意味著“變化”和“重覆”,每個分支條件都代表一個變化,每個分支邏輯都是相似行為或演算法的重覆。當追加新的條件時,我們需要追... ...
  • 外觀模式:為子系統中的一組介面提供一個一致的界面,此模式定義了一個高層介面,這個介面使得這一個子系統更加容易使用。 外觀模式在什麼時候使用最好了? 首先,在設計初期階段,應該要有意識的將不同的兩個層分離。 其次,在開發階段,子系統往往因為不斷的重構演化而變得越來越複雜。 第三,在維護一個遺留的大型系 ...
  • 模板方法模式,定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個演算法的結構即可重新定義該演算法的某些特定步驟。 模板方法模式是通過把不變行為搬到超類,去除子類中的重覆代碼來體現它的優勢。 當不變和可變的行為在方法的子類實現中混合在一起的時候,不變的行為就會在子類中重覆 ...
  • 原型模式其實就是從一個對象再創建另外一個可定製的對象,而且不需要知道任何創建的細節。 .NET在System命名空間中提供了ICloneable介面,其中就是唯一的一個方法Clone(),這樣你就只需要實現這個介面就可以完成原型模式。(選至《大話設計模式》) MemberwiseClone()方法, ...
  • 摘要:本文介紹了簡單工廠模式的概念,優缺點,實現方式,以及結合Annotation和反射的改良方案(讓簡單工廠模式不簡單)。同時介紹了簡單工廠模式(未)遵循的OOP原則。最後給出了簡單工廠模式在JDBC中的應用 原創文章。同步自作者個人博客 "http://www.jasongj.com/desig ...
  • "設計模式系列目錄" 新博客 "wossoneri.com" 單一職責原則 Single Responsibility Principle SRP 就一個類而言,應該僅有一個引起它變化的原因。 假設現在要在iPhone上做一個圖片編輯工具。功能有裁剪圖片,旋轉圖片,縮放移動照片等等。 吶,我們可以寫 ...
  • 利用繼承來提供對象的行為,會導致: 1、代碼在多個子類中重覆 2、很難知道所有鴨子的全部行為 3、運行時的行為不易改變 4、改變會牽一發而動全身,造成其他鴨子不想要的改變 設計原則 1 :找出應用之中可能需要變化之處,把他們獨立出來,不要和那些不需要變化的代碼混在一起。 註釋:把會變化的部分取出並“ ...
  • (原文地址:http://www.cnblogs.com/hellohuang/p/5492302.html ) 這是一個簡單實現有分步式框架,由5個服務進程組成一個伺服器,它們分別是世界服(Ws),資料庫處理服(Dp),場景服(Ss),網關服(Fep),框架的思想用來自工作項目框架(但沒有它的代碼 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...