从0开始学PHP面向对象内容之常用设计模式(组合,外观,代理) ...

打印 上一主题 下一主题

主题 859|帖子 859|积分 2577


二、结构型设计模式

4、组合模式(Composite)

   组合模式(Composite Pattern)是一种结构型设计模式,它将对象组合成树形结构以表现”部分–整体“的条理结构。通过组合模式,客户端可以以同等的方式处理单个对象和对象的组合
  组合模式的核心概念

   1、组合模式答应客户端同意对待单个对象和对象组合,而不需要分别对待。
2、树形结构是其核心,通过递归调用处理每个对象节点。
3、组合模式适用于需要表现”部分–整体“关系的场景,例如文件体系,组织结构体系等
  组成角色

   1、组件(Componet):定义所有检点的通用接口,声明默认活动。
2、叶子节点(Leaf):表现树的叶子节点,具体的对象,不能包含子节点。
3、组合节点(Composite):表现树的中央节点,可以包含其他叶子节点或组合节点
4、客户端(Client):使用组件接口来统一操作树形结构中的元素
  实现

以下以“文件体系”为例,展示组合模式的实现
1、定义接口:定义所有节点的通用接口
  1. // 组件接口
  2. interface FileSystemComponent {
  3.     public function display($indent = 0);
  4. }
复制代码
2、叶子节点:表现单个文件,不能包含子节点。
  1. // 叶子节点
  2. class File implements FileSystemComponent {
  3.     private $name;
  4.     public function __construct($name) {
  5.         $this->name = $name;
  6.     }
  7.     public function display($indent = 0) {
  8.         echo str_repeat(" ", $indent) . "File: " . $this->name . PHP_EOL;
  9.     }
  10. }
复制代码
3、组合节点:表现文件夹,可以包含文件或子文件夹
  1. // 组合节点
  2. class Directory implements FileSystemComponent {
  3.     private $name;
  4.     private $children = [];
  5.     public function __construct($name) {
  6.         $this->name = $name;
  7.     }
  8.     public function add(FileSystemComponent $component) {
  9.         $this->children[] = $component;
  10.     }
  11.     public function display($indent = 0) {
  12.         echo str_repeat(" ", $indent) . "Directory: " . $this->name . PHP_EOL;
  13.         foreach ($this->children as $child) {
  14.             $child->display($indent + 2);
  15.         }
  16.     }
  17. }
复制代码
4、客户端:使用组合模式创建和操作文件体系
  1. // 创建文件和目录
  2. $root = new Directory("root");
  3. $home = new Directory("home");
  4. $root->add($home);
  5. $file1 = new File("file1.txt");
  6. $file2 = new File("file2.txt");
  7. $home->add($file1);
  8. $home->add($file2);
  9. $subDir = new Directory("documents");
  10. $home->add($subDir);
  11. $file3 = new File("resume.docx");
  12. $subDir->add($file3);
  13. // 显示文件系统结构
  14. $root->display();
复制代码
输出结果
  1. Directory: root
  2.    Directory: home
  3.     File: file1.txt
  4.     File: file2.txt
  5.     Directory: documents
  6.       File: resume.docx
复制代码
组合模式的应用场景

   1、user_deposit:文件和文件夹的条理结构
2、图形界面(GUI):界面中的窗口,按钮,文本框等组件的条理结构
3、组织架构:公司部门与员工的条理关系。
4、菜单体系:菜单与子菜单的条理结构
  扩展

1、添加移除功能:答应动态添加、移除子节点
  1. class Directory implements FileSystemComponent {
  2.     public function remove(FileSystemComponent $component) {
  3.         $this->children = array_filter($this->children, fn($child) => $child !== $component);
  4.     }
  5. }
复制代码
2、缓存机制:在组合节点中添加缓存,进步查询效率
  1. class Directory {
  2.     private $sizeCache;
  3.     public function calculateSize() {
  4.         if ($this->sizeCache === null) {
  5.             $this->sizeCache = array_reduce($this->children, fn($carry, $child) => $carry + $child->calculateSize(), 0);
  6.         }
  7.         return $this->sizeCache;
  8.     }
  9. }
复制代码
小结

   组合模式通过树形结构将单个对象与组合对象统一处理,简化了客户端代码的复杂性,尤其适用于具有条理关系的体系。PHP实现组合模式非常机动,可以根据现实需求动态调整子节点的添加、移除以及递归活动,极大地进步了代码的扩展性和复用性。
  5、外观模式(Facade)

   外观模式(Face Pattern)是一种结构型设计模式,通过为子体系中的一组复杂接口提供一个同等的接口,简化了客户端与子体系之间的交互,它隐蔽了子体系的复杂性,使得客户端只需要与外观对象交互即可完成操作
  外观模式的定义

   1、核心思想:为复杂体系提供一个统一的高层接口,使得客户端可以通过该接口访问子体系,而无需直接与子体系交互
2、主要目标:低落体系的复杂性,进步体系的可维护性和易用性
  外观模式的组成

   1、外观类(Facade):提供一个简单的接口,封装子体系的功能。
2、子体系类(Subsystem):完成体系的现实功能,但客户端无需访问这些类
3、客户端(Client ):通过外观类与子体系交互而不直接依赖子体系的具体实现
  实现

以下通过一个“智能家居体系”的例子展示外观模式的实现。
子体系类:包含 灯光,空调等
  1. class Light {
  2.     public function on() {
  3.         echo "Light is turned on.\n";
  4.     }
  5.     public function off() {
  6.         echo "Light is turned off.\n";
  7.     }
  8. }
  9. class AirConditioner {
  10.     public function on() {
  11.         echo "Air Conditioner is turned on.\n";
  12.     }
  13.     public function off() {
  14.         echo "Air Conditioner is turned off.\n";
  15.     }
  16. }
  17. class Television {
  18.     public function on() {
  19.         echo "Television is turned on.\n";
  20.     }
  21.     public function off() {
  22.         echo "Television is turned off.\n";
  23.     }
  24. }
复制代码
外观类 :使用场景 开始场景(打开),结束场景(关闭)
  1. class SmartHomeFacade {
  2.     private $light;
  3.     private $airConditioner;
  4.     private $television;
  5.     public function __construct() {
  6.         $this->light = new Light();
  7.         $this->airConditioner = new AirConditioner();
  8.         $this->television = new Television();
  9.     }
  10.     public function startDay() {
  11.         echo "Starting the day...\n";
  12.         $this->light->on();
  13.         $this->airConditioner->on();
  14.         $this->television->on();
  15.     }
  16.     public function endDay() {
  17.         echo "Ending the day...\n";
  18.         $this->television->off();
  19.         $this->airConditioner->off();
  20.         $this->light->off();
  21.     }
  22. }
复制代码
客户端代码
  1. $smartHome = new SmartHomeFacade();
  2. // 启动智能家居
  3. $smartHome->startDay();
  4. // 结束智能家居
  5. $smartHome->endDay();
复制代码
运行结果

  1. Starting the day...
  2. Light is turned on.
  3. Air Conditioner is turned on.
  4. Television is turned on.
  5. Ending the day...
  6. Television is turned off.
  7. Air Conditioner is turned off.
  8. Light is turned off.
复制代码
外观模式的应用场景

1、复杂体系的简化接口:大型体系中,多个子体系需要对外提供功能时,可以通过外观类统一接口,低落复杂度
2、模块解耦:不同模块之间通过外观类交互,而不直接依赖子体系的具体实现。
3、跨层访问:在分层架构中,外观模式可以用作每一层的入口点
小结

   外观模式通过隐蔽子体系的实现细节,为客户端提供了一个简单易用的接口。
它是“高内聚、低耦合”的典范,可以显著低落客户端与子体系之间的耦合度。
在现实开发中,外观模式常用于大型复杂体系、分层架构中,提供模块化和易用性的统一入口。
  6、代理模式(Proxy)

   代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。通过代理模式,客户端可以通过代理对象间接与真实对象交互,从而实现对对象的访问控制、耽误加载、功能增强等需求。
  代理模式定义

   1、核心思想:代理对象是现实对象的代表,负责对真实对象的访问或操作,同时可以添加额外的功能
2、主要目标:控制访问,性能优化或者为对象提供附加功能。
  代理模式组成

   1、抽象主题(Subject):定义代理类和真实主题的共同接口
2、真实主题(RealSubject):实现抽象主题的具体功能,是现实被访问的对象
3、代理类(Proxy):实现抽象主题,控制对真实主题的访问
  代理模式的类型

1、长途代理(Remote Proxy)

   1、定义:为位于不同地址空间的对象提供本地代理。
2、示例:长途调用(RPC)或Web服务代理。
3、场景:通过网络访问长途对象(如RPC、RMI)。
  2、虚拟代理(Virtual Proxy

   1、定义:在需要时才创建对象(耽误加载)。
2、示例:大图像的耽误加载。
3、场景:需要耽误加载资源时(如大文件或复杂对象)。
  3、保护代理(Protection Proxy)

   1、定义:控制对对象的访问权限。
2、示例:基于用户权限的访问控制。
3、场景:控制对敏感资源的访问,通常结合权限控制。
  4、智能引用代理(Smart Proxy):

   1、定义:在访问对象时提供附加功能(如日记记录、统计)。
2、示例:记录对象调用次数
3、场景:在访问真实对象前后,实行附加逻辑(如日记记录、调用统计)。
  代理模式的设计要点

   1、 共享接口:代理类和真实对象应实现相同的接口或继承自相同的抽象类。
2、透明性:客户端代码无需感知代理类的存在,操作与直接访问真实对象同等。
3、耽误加载:虚拟代理应只管推迟真实对象的创建,淘汰资源浪费。
  实现

以下通过一个“图像查看器”的例子展示代理模式的实现
抽象主题
  1. interface Image {
  2.     public function display();
  3. }
复制代码
真实主题
  1. class RealImage implements Image {
  2.     private $fileName;
  3.     public function __construct($fileName) {
  4.         $this->fileName = $fileName;
  5.         $this->loadFromDisk($fileName);
  6.     }
  7.     private function loadFromDisk($fileName) {
  8.         echo "Loading image from disk: $fileName\n";
  9.     }
  10.     public function display() {
  11.         echo "Displaying image: $this->fileName\n";
  12.     }
  13. }
复制代码
代理类
  1. class ProxyImage implements Image {
  2.     private $realImage;
  3.     private $fileName;
  4.     public function __construct($fileName) {
  5.         $this->fileName = $fileName;
  6.     }
  7.     public function display() {
  8.         if ($this->realImage === null) {
  9.             $this->realImage = new RealImage($this->fileName);
  10.         }
  11.         $this->realImage->display();
  12.     }
  13. }
复制代码
客户端代码
  1. $image = new ProxyImage("photo.jpg");
  2. // 第一次调用,会加载图像
  3. $image->display();
  4. // 第二次调用,不会重新加载图像
  5. $image->display();
复制代码
运行结果:
  1. Loading image from disk: photo.jpg
  2. Displaying image: photo.jpg
  3. Displaying image: photo.jpg
复制代码
代理模式的扩展

动态代理:使用 PHP 的把戏方法(如 __call)实现通用代理,拦截方法调用。
  1. class DynamicProxy {
  2.     private $realObject;
  3.     public function __construct($realObject) {
  4.         $this->realObject = $realObject;
  5.     }
  6.     public function __call($name, $arguments) {
  7.         echo "Logging: Calling method $name\n";
  8.         return call_user_func_array([$this->realObject, $name], $arguments);
  9.     }
  10. }
  11. // 示例
  12. $realImage = new RealImage("example.jpg");
  13. $proxy = new DynamicProxy($realImage);
  14. $proxy->display();
复制代码
运行结果:
  1. Loading image from disk: example.jpg
  2. Logging: Calling method display
  3. Displaying image: example.jpg
复制代码
小结

   代理模式通过在真实对象和客户端之间增加代理对象,实现了对对象访问的控制、耽误加载、权限校验等功能。在现实开发中,代理模式广泛应用于长途调用、资源管理、权限控制等场景,特别是在需要解耦客户端与真实对象时,是一个非常实用的设计模式。
  总结

代理模式与其他模式的对比


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

莫张周刘王

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表