代理模式屬於結構性設計模式,針對類別與物件組合在一起的經典結構。代理模式也是一種使用較多的設計模式,需要我們重點掌握,他可以在不改變目標物件的情況下,加入一些額外的功能。
定義
代理模式(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中文網其他相關文章!

许多Windows11用户报告在系统启动时或尝试通过命令提示符执行命令时看到错误消息“写入代理设置时出错-访问被拒绝”。通常,当尝试运行任何命令或升级到Windows操作系统后,某些安装不正确的第3方应用程序可能会干扰命令提示符时,会出现此错误。您是否对Windows11计算机上的此错误写入代理设置消息感到困扰?然后,您已到达正确的位置。在本文中,我们策划了一些可能的解决方案,可帮助您解决计算机上的此问题。修复1–更改Windows的默认终端应用程序您是否从Windo

代理模式是一种Java框架设计模式,通过创建代理对象在客户端和目标对象之间进行中介。它的优势包括:保护目标对象,提供数据完整性和安全性;控制对目标的访问,实现权限控制和安全措施;增强目标行为,添加额外功能如日志记录、缓存和事务管理;简化测试,便于mocking和stubbing目标。然而,代理模式也存在劣势:开销:创建和维护代理对象可能降低性能;复杂性:需要深入理解设计模式;限制对目标的访问,可能在某些情况下不合适。

导言PHP设计模式是一组经过验证的解决方案,用于解决软件开发中常见的挑战。通过遵循这些模式,开发者可以创建优雅、健壮和可维护的代码。它们帮助开发者遵循SOLID原则(单一职责、开放-封闭、Liskov替换、接口隔离和依赖反转),从而提高代码的可读性、可维护性和可扩展性。设计模式的类型有许多不同的设计模式,每种模式都有其独特的目的和优点。以下是一些最常用的php设计模式:单例模式:确保一个类只有一个实例,并提供一种全局访问此实例的方法。工厂模式:创建一个对象,而不指定其确切类。它允许开发者根据条件

PHP是一种广泛使用且非常流行的编程语言。当今的Web应用程序中,PHP是非常重要的一部分。在开发PHP应用程序的过程中,设计模式起着至关重要的作用。设计模式是解决问题的一种模板,在不同的环境中可重复使用,帮助我们写出更好的代码,使代码更加可靠、可维护、可扩展。在本文中,我们将探讨一些PHP中常用的设计模式及其实现方法。单例模式单例模式是一种创建模式,它允许

Java中的代理模式代理是设计模式中的一种,它允许对象以另一个对象的形式出现,通过代理对象来访问原始对象。代理在许多应用程序中都得到广泛使用,其中最常见的应用是在网络中实现远程对象调用和日志记录。Java中也有许多使用代理模式的例子。Java中的代理模式主要是通过以下三种方式实现的:静态代理静态代理是通过在编译阶段创建代理类来实现的。代理类和原始类实现

php设计模式有:1、单例模式,确保一个类只有一个实例化对象;2、工厂模式,将对象的实例化过程封装在一个工厂类中;3、抽象工厂模式,是一种类似于工厂模式的创建对象的模式;4、观察者模式,实现对象之间的一对多依赖关系;5、适配器模式,将一个类的接口转换成另一个类的接口;6、装饰器模式,动态地给一个对象添加一些额外的功能;7、迭代器模式;8、策略模式;9、模板方法模式等等。

随着技术的不断发展,设计模式在软件开发中变得越来越重要。PHP7.0作为最新的PHP版本,也集成了许多的设计模式。在本文中,我们将探讨PHP7.0中的设计模式,以帮助PHP程序员更好地理解和应用这些模式。单例模式单例模式是一种创建型模式,它确保一个类只有一个实例,并提供了一个全局访问点。在PHP7.0中,可以使用__construct方法和static方法来

PHP核心的设计模式与实践引言:设计模式是软件开发中常用的解决问题的模板,它们提供了一种可重用的解决方案,可以帮助我们在开发过程中遵循最佳实践和良好的软件设计原则。PHP作为一种广泛应用的编程语言,也有许多常见和有用的设计模式可以在核心开发中使用。本文将介绍几种常见的PHP设计模式,并提供相关的代码示例。一、单例模式(Singleton)单例模式是一种只允许


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

Dreamweaver Mac版
視覺化網頁開發工具