一文讀懂php設計模式之代理模式
代理模式屬於結構性設計模式,針對類別與物件組合在一起的經典結構。代理模式也是一種使用較多的設計模式,需要我們重點掌握,他可以在不改變目標物件的情況下,加入一些額外的功能。
定義
代理模式(Proxy)為其他物件提供一種代理以控制對這個物件的存取。使用代理模式建立代理對象,讓代理對象控制目標對象的存取(目標對象可以是遠端的對象、建立開銷大的對像或需要安全控制的對象),並且可以在不改變目標對象的情況下添加一些額外的功能。
問題
目前系統關於使用者登入註冊的業務,有一個Login類別。偽代碼如下:
class UserLogin { // …… 省略属性和部分方法 public function login ($name, $pass) { // 登录业务 } public function reg ($name, $pass) { // 注册业务 } }
現在,我們想在使用者登入和註冊的業務中加入一個功能-限流,讓客戶端呼叫該方法的頻次限制在一秒鐘最多5次。現在,我們來實現該功能,偽代碼如下:
class UserLogin { // …… 省略属性和部分方法 public function login ($name, $pass) { // 限流 $limit = new Limit(); if ($limit->restrict()) { // …… } // 登录业务 } public function reg ($name, $pass) { // 限流 $limit = new Limit(); if ($limit->restrict()) { // …… } // 注册业务 } }
大家看看上面的程式碼,它有幾個問題,首先,限流程式碼侵入到業務程式碼中,跟業務程式碼高度耦合。其次,限流和業務代碼無關,違反單一職責原則。
實作
接下來,我們用代理模式重寫上面的程式碼,重寫後的程式碼如下所示:
interface IUserLogin { function login (); function register (); } class UserLogin implements IUserLogin { // …… 省略属性和部分方法 public function reg ($uname, $pass) { // 注册业务 } public function login ($uname, $pass) { // 登录业务 } } class UserLoginProxy implements IUserLogin { private $limit = null; private $login = null; public function __construct(Limit $limit, Login $login) { $this->limit = $limit; $this->login = $login; } public function login($uname, $pass) { if ($this->limit->restrict()) { // ... } return $this->login->login($uname, $pass); } public function register($uname, $pass) { if ($this->limit->restrict()) { // ... } return $this->login->register($uname, $pass); } }
上面的方法是基於接口而非實現程式設計的設計思想,但如果原始類別並沒有定義接口,或者這個類別並不是我們開發和維護的,那麼要怎麼實現代理模式呢?
對於這種外部類別的擴展,我們一般會採用繼承的方法來實作。
class UserLogin { public function reg ($uname, $pass) { // 注册业务 } public function login ($uname, $pass) { // 登录业务 } } class UserLoginProxy extends Login { private $limit = null; public function __construct(Limit $limit, Login $login) { $this->limit = $limit; $this->login = $login; } public function login($uname, $pass) { if ($this->limit->restrict()) { // ... } return parent::login($uname, $pass); } public function reg($uname, $pass) { if ($this->limit->restrict()) { // ... } return parent::register($uname, $pass); } }
大家看看上面的程式碼,是不是還有什麼問題?你會發現
if ($this->limit->restrict()) { // ... }
這段相似的程式碼,出現了兩次。現在我們只是為兩個方法增加了限流功能,如果UserLogin類別有10個方法,每個方法我們都想要新增限流的功能,那麼我們就需要重複複製10次該段程式碼。如果,我們想要為10給類別中所有方法都加入限流功能,每個類別中都有10個方法,那麼上面的限流程式碼將會重複100次。
當然,你會說我可以將限流的程式碼封裝到一個函數裡不就解決了上述問題麼?但還有一個問題解決不了,原始類別裡每個方法在代理類別中都要重新實作一遍。就像上面原始類別裡有reg、login方法,代理類別裡也有reg、login方法。
動態代理程式
如何解決上述的問題,我們可以藉助動態代理來解決。想要使用動態代理,就要理解並使用PHP中的反射機制。
php具有完整的反射 API,增加了對類別、介面、函數、方法和擴充進行反向工程的能力。此外,反射 API 提供了方法來取出函數、類別和方法中的文件註解。關於php的反射相關知識,這裡就不詳述了,大家可以自行查閱相關資訊。
注意,使用反射對效能消耗很大,一般情況下請不要使用。
下面我們來展示如何用反射實作動態代理,偽代碼如下:
class UserLogin { public function reg ($uname, $pass) { // 注册业务 echo '注册业务' . PHP_EOL; } public function login ($uname, $pass) { // 登录业务 echo '登录业务' . PHP_EOL; } } class LimitProxy { // 用来保存多个实例对象 private $target = []; public function __construct(Object $obj) { $this->target[] = $obj; } public function __call($name, $arguments) { foreach ($this->target as $obj) { $ref = new \ReflectionClass($obj); if ($method = $ref->getMethod($name)) { if ($method->isPublic() && !$method->isAbstract()) { // 限流 echo "这里是限流业务处理" . PHP_EOL; $result = $method->isStatic() ? $method->invoke(null, $obj, ...$arguments) : $method->invoke($obj, ...$arguments); return $result; } } } } }
測試程式碼如下:
$login = new Login(); $loginProxy = new LimitProxy($login); $loginProxy->reg('gwx', '111111'); $loginProxy->login('james', '111111111');
應用程式場景
存取控制(保護代理程式)。例如係統有一個訂單的模組,原本該模組也有權限控制,但現在我們希望只針對指定ip的客戶端可以訪問,那麼我們可以使用代理模式。
本機執行遠端服務 (遠端代理)適用於服務物件位於遠端伺服器上的情況。
在業務程式碼中開發一些非功能性的需求,例如:限流、統計、日誌記錄
快取方面的應用,例如新增一個快取代理,當快取存在時,就呼叫快取代理來取得快取的數據,當快取不存在時,就呼叫原始介面。
以上是一文讀懂php設計模式之代理模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

許多Windows11使用者報告在系統啟動時或嘗試透過命令提示字元執行命令時看到錯誤訊息「寫入代理設定時出錯-存取被拒絕」。通常,當嘗試執行任何命令或升級到Windows作業系統後,某些安裝不正確的第3方應用程式可能會幹擾命令提示字元時,會出現此錯誤。您是否對Windows11電腦上的此錯誤寫入代理設定訊息感到困擾?然後,您已到達正確的位置。在本文中,我們策劃了一些可能的解決方案,可協助您解決電腦上的此問題。修復1–更改Windows的預設終端應用程式您是否從Windo

PHP是一種廣泛使用且非常流行的程式語言。在當今的Web應用程式中,PHP是非常重要的一部分。在開發PHP應用程式的過程中,設計模式起著至關重要的作用。設計模式是解決問題的一種模板,在不同的環境中可重複使用,幫助我們寫出更好的程式碼,使程式碼更加可靠、可維護、可擴展。在本文中,我們將探討一些PHP中常用的設計模式及其實作方法。單例模式單例模式是一種創建模式,它允許

代理模式是一種Java框架設計模式,透過建立代理物件在客戶端和目標物件之間進行中介。它的優點包括:保護目標對象,提供資料完整性和安全性;控制對目標的訪問,實現權限控制和安全措施;增強目標行為,添加額外功能如日誌記錄、快取和事務管理;簡化測試,便於mocking和stubbing目標。然而,代理模式也存在劣勢:開銷:建立和維護代理物件可能降低效能;複雜性:需要深入理解設計模式;限制對目標的訪問,可能在某些情況下不合適。

導言PHP設計模式是一組經過驗證的解決方案,用於解決軟體開發中常見的挑戰。透過遵循這些模式,開發者可以創建優雅、健壯和可維護的程式碼。它們可協助開發者遵循SOLID原則(單一職責、開放-封閉、Liskov替換、介面隔離和依賴反轉),從而提高程式碼的可讀性、可維護性和可擴展性。設計模式的類型有許多不同的設計模式,每種模式都有其獨特的目的和優點。以下是一些最常用的php設計模式:單例模式:確保一個類別只有一個實例,並提供一種全域存取此實例的方法。工廠模式:建立一個對象,而不指定其確切類別。它允許開發者根據條件

Java中的代理模式代理是設計模式中的一種,它允許物件以另一個物件的形式出現,透過代理物件來存取原始物件。代理在許多應用程式中都被廣泛使用,其中最常見的應用是在網路中實現遠端物件呼叫和日誌記錄。 Java中也有許多使用代理模式的例子。 Java中的代理模式主要是透過以下三種方式實現的:靜態代理靜態代理程式是透過在編譯階段建立代理類別來實現的。代理類別和原始類別實現

php設計模式有:1、單例模式,確保一個類別只有一個實例化物件;2、工廠模式,將物件的實例化過程封裝在一個工廠類別中;3、抽象工廠模式,是一種類似工廠模式的創建物件的模式;4、觀察者模式,實現物件之間的一對多依賴關係;5、適配器模式,將一個類別的介面轉換成另一個類別的介面;6、裝飾器模式,動態地給一個物件一些額外的功能;7、迭代器模式;8、策略模式;9、模板方法模式等等。

PHP核心的設計模式與實踐引言:設計模式是軟體開發中常用的解決問題的模板,它們提供了一種可重複使用的解決方案,可以幫助我們在開發過程中遵循最佳實踐和良好的軟體設計原則。 PHP作為一種廣泛應用的程式語言,也有許多常見且有用的設計模式可以在核心開發中使用。本文將介紹幾種常見的PHP設計模式,並提供相關的程式碼範例。一、單例模式(Singleton)單例模式是一種只允許

隨著技術的不斷發展,設計模式在軟體開發中變得越來越重要。 PHP7.0作為最新的PHP版本,也整合了許多的設計模式。在本文中,我們將探討PHP7.0中的設計模式,以幫助PHP程式設計師更好地理解並應用這些模式。單例模式單例模式是一種建立型模式,它確保一個類別只有一個實例,並提供了一個全域存取點。在PHP7.0中,可以使用__construct方法和static方法來
