PHP设计模式(七)组合模式Composite实例详解【结构型】


Posted in PHP onMay 02, 2020

本文实例讲述了PHP设计模式:组合模式Composite。分享给大家供大家参考,具体如下:

1. 概述

在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面。

例子1:就是多级树形菜单。

例子2:文件和文件夹目录

2.问题

我们可以使用简单的对象组合成复杂的对象,而这个复杂对象有可以组合成更大的对象。我们可以把简单这些对象定义成类,然后定义一些容器类来存储这些简单对象。客户端代码必须区别对象简单对象和容器对象,而实际上大多数情况下用户认为它们是一样的。对这些类区别使用,使得程序更加复杂。递归使用的时候跟麻烦,而我们如何使用递归组合,使得用户不必对这些类进行区别呢?

3.   解决方案

        组合模式:将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。

        有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。

组合模式让你可以优化处理递归或分级数据结构。有许多关于分级数据结构的例子,使得组合模式非常有用武之地。关于分级数据结构的一个普遍性的例子是你每次使用电脑时所遇到的:文件系统。文件系统由目录和文件组成。每个目录都可以装内容。目录的内容可以是文件,也可以是目录。按照这种方式,计算机的文件系统就是以递归结构来组织的。如果你想要描述这样的数据结构,那么你可以使用组合模式Composite。

4.  组合模式的分类

1)    将管理子元素的方法定义在Composite类中
2)    将管理子元素的方法定义在Component接口中,这样Leaf类就需要对这些方法空实现。

5. 适用性

以下情况下适用Composite模式:

1).你想表示对象的部分-整体层次结构

2).你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

6. 结构

PHP设计模式(七)组合模式Composite实例详解【结构型】

典型的Composite对象结构如下图所示:

PHP设计模式(七)组合模式Composite实例详解【结构型】

7. 构建模式的组成

          抽象构件角色(component):是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。

          这个接口可  以用来管理所有的子对象。(可选)在递归结构中定义一个接口,用于访问一个父部件,并在合适的情况下实现它。  

          树叶构件角色(Leaf):在组合树中表示叶节点对象,叶节点没有子节点。并在组合中定义图元对象的行为。
          树枝构件角色(Composite):定义有子部件的那些部件的行为。存储子部件。在Component接口中实现与子部件有关的操作。
          客户角色(Client):通过component接口操纵组合部件的对象。   

8. 效果

     1) • 定义了包含基本对象和组合对象的类层次结构 基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断的递归下去。客户代码中,任何用到   基本对象的地方都可以使用组合对象。
     2) • 简化客户代码 客户可以一致地使用组合结构和单个对象。通常用户不知道 (也不关心)处理的是一个叶节点还是一个组合组件。这就简化了客户代码 , 因为在定义组合的那些类中不需要写一些充斥着选择语句的函数。
    3) • 使得更容易增加新类型的组件 新定义的Composite或Leaf子类自动地与已有的结构和客户代码一起工作,客户程序不需因新的Component类而改变。
    4) • 使你的设计变得更加一般化 容易增加新组件也会产生一些问题,那就是很难限制组合中的组件。有时你希望一个组合只能有某些特定的组件。使用Composite时,你不能依赖类型系统施加这些约束,而必须在运行时刻进行检查。

9. 实现

比较经典的例子是树形菜单。多级展示,这个菜单可以无限增加节点;例外就是文件遍历等等。

<?php 
/**
 * 组合模式 
 * 
 * @author guisu
 * @version 1.0
 * 组合模式:树形菜单
 * 
 * 将对象组合成树形结构以表示"部分-整体"的层次结构,使得客户对单个对象和复合对象的使用具有一致性 
 */ 
/**
 * 抽象构件角色(component)
 *
 */
abstract class MenuComponent
{
 public function add($component){}
 public function remove($component){}
 public function getName(){}
 public function getUrl(){}
 public function displayOperation(){}
}
/**
 * 树枝构件角色(Composite)
 *
 */
class MenuComposite extends MenuComponent
{
 private $_items = array();
 private $_name = null;
 private $_align = '';
 public function __construct($name) {
 $this->_name = $name;
 }
 public function add($component) {
 $this->_items[$component->getName()] = $component;
 }
 public function remove($component) {
 $key = array_search($component,$this->_items);
 if($key !== false) unset($this->_items[$key]);
 }
 public function getItems() {
 return $this->_items;
 }
 
 public function displayOperation() {
 static $align = '|';
 if($this->getItems()) {
  //substr($align, strpos($align,));
  $align .= ' _ _ ';
 }else{
  $align .='';
 }
 echo $this->_name, " <br/>";
 foreach($this->_items as $name=> $item) {
  echo $align;
  $item->displayOperation();
 }
 }
 
 public function getName(){
 return $this->_name;
 }
}
 
/**
 *树叶构件角色(Leaf)
 *
 */
class ItemLeaf extends MenuComponent
{
 private $_name = null;
 private $_url = null;
 //public $_align = '----';
 public function __construct($name,$url)
 {
 $this->_name = $name;
 $this->_url = $url;
 }
 
 public function displayOperation()
 {
 echo '<a href="', $this->_url, '" rel="external nofollow" >' , $this->_name, '</a><br/>';
 }
 
 public function getName(){
 return $this->_name;
 }
}
 
class Client
{
 public static function displayMenu()
 {
 $subMenu1 = new MenuComposite("submenu1");
 $subMenu2 = new MenuComposite("submenu2");
 $subMenu3 = new MenuComposite("submenu3");
 
 $subMenu4 = new MenuComposite("submenu4");
 $subMenu5 = new MenuComposite("submenu5");
 /*
 $item1 = new ItemLeaf("sohu","www.163.com");
 $item2 = new ItemLeaf("sina","www.sina.com");
 
 $subMenu4 = new MenuComposite("submenu4");
 $subMenu1->add($subMenu4);
 
 $subMenu4->add($item1);
 $subMenu4->add($item2);
 */
 $item3 = new ItemLeaf("baidu","www.baidu.com");
 $item4 = new ItemLeaf("google","www.google.com");
 $subMenu2->add($item3);
 $subMenu2->add($item4);
 
 $allMenu = new MenuComposite("AllMenu");
 $allMenu->add($subMenu1);
 $allMenu->add($subMenu2);
 $allMenu->add($subMenu3);
 $subMenu3->add($subMenu4);
 $subMenu4->add($subMenu5);
 $allMenu->displayOperation();
 }
}
// 创建menu
Client::displayMenu();
?>

10. 组合模式和其他相关模式

1)装饰模式(Decorator模式)经常与Composite模式一起使用。当装饰和组合一起使用时,它们

通常有一个公共的父类。因此装饰必须支持具有 Add、Remove和GetChild 操作的Component接口。

2)Flyweight模式让你共享组件,但不再能引用他们的父部件。

3)(迭代器模式)Itertor可用来遍历Composite。

4)(观察者模式)Visitor将本来应该分布在Composite和L e a f类中的操作和行为局部化。

11. 总结

组合模式解耦了客户程序与复杂元素内部结构,从而使客户程序可以向处理简单元素一样来处理复杂元素。

如果你想要创建层次结构,并可以在其中以相同的方式对待所有元素,那么组合模式就是最理想的选择。

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
PHP+MYSQL的文章管理系统(一)
Oct 09 PHP
PHP mail 通过Windows的SMTP发送邮件失败的解决方案
May 27 PHP
PHP与C#分别格式化文件大小的代码
May 14 PHP
Look And Say 序列php实现代码
May 22 PHP
php生成zip压缩文件的方法详解
Jun 09 PHP
php计算函数执行时间的方法
Mar 20 PHP
使用PHP生成二维码的方法汇总
Jul 22 PHP
CI(Codeigniter)的Setting增强配置类实例
Jan 06 PHP
YII中Ueditor富文本编辑器文件和图片上传的配置图文教程
Mar 15 PHP
PHP jpgraph库的配置及生成统计图表:折线图、柱状图、饼状图
May 15 PHP
PHP实现实时生成并下载超大数据量的EXCEL文件详解
Oct 23 PHP
PHP常见数组排序方法小结
Aug 20 PHP
PHP设计模式(六)桥连模式Bridge实例详解【结构型】
May 02 #PHP
PHP设计模式(五)适配器模式Adapter实例详解【结构型】
May 02 #PHP
PHP设计模式(四)原型模式Prototype实例详解【创建型】
May 02 #PHP
PHP设计模式(三)建造者模式Builder实例详解【创建型】
May 02 #PHP
PHP设计模式(一)工厂模式Factory实例详解【创建型】
May 02 #PHP
PHP设计模式概论【概念、分类、原则等】
May 01 #PHP
PHP设计模式之 策略模式Strategy详解【对象行为型】
May 01 #PHP
You might like
在PHP中利用XML技术构造远程服务(下)
2006/10/09 PHP
PHP入门速成教程
2007/03/19 PHP
PHP 只允许指定IP访问(允许*号通配符过滤IP)
2014/07/08 PHP
PHP中error_reporting()用法详解
2015/08/31 PHP
PHP多维数组遍历方法(2种实现方法)
2015/12/10 PHP
深入了解PHP中的Array数组和foreach
2016/11/06 PHP
PHP脚本自动识别验证码查询汽车违章
2016/12/20 PHP
PHP封装的page分页类定义与用法完整示例
2018/12/24 PHP
Javascript中的相等与不等运算
2010/04/25 Javascript
jquery 插件开发 extjs中的extend用法小结
2013/01/04 Javascript
js异常捕获方法介绍
2013/04/10 Javascript
js实现微信分享代码
2020/10/11 Javascript
基于javascript实现listbox左右移动
2016/01/29 Javascript
jQuery实现鼠标经过像翻页和描点链接效果
2016/08/08 Javascript
jQuery多级联动下拉插件chained用法示例
2016/08/20 Javascript
etmvc+jQuery EasyUI+combobox多值操作实现角色授权实例
2016/11/09 Javascript
解决Window10系统下Node安装报错的问题分析
2016/12/13 Javascript
详解nodejs 文本操作模块-fs模块(一)
2016/12/22 NodeJs
Java中int与integer的区别(基本数据类型与引用数据类型)
2017/02/19 Javascript
Vue.js弹出模态框组件开发的示例代码
2017/07/26 Javascript
微信小程序tabBar底部导航中文注解api详解
2017/08/16 Javascript
nodejs结合Socket.IO实现的即时通讯功能详解
2018/01/12 NodeJs
使用Vue.js开发微信小程序开源框架mpvue解析
2018/03/20 Javascript
vue拖拽组件 vuedraggable API options实现盒子之间相互拖拽排序
2019/07/08 Javascript
layer页面跳转,获取html子节点元素的值方法
2019/09/27 Javascript
javascript sort()对数组中的元素进行排序详解
2019/10/13 Javascript
如何在VUE中使用vue-awesome-swiper
2021/01/04 Vue.js
[01:45:05]VGJ.T vs Newbee Supermajor 败者组 BO3 第二场 6.6
2018/06/07 DOTA
python编写暴力破解FTP密码小工具
2014/11/19 Python
Python利用Nagios增加微信报警通知的功能
2016/02/18 Python
python实现图像随机裁剪的示例代码
2020/12/10 Python
VSCODE配置Markdown及Markdown基础语法详解
2021/01/19 Python
严以用权专题学习研讨会发言材料
2015/11/09 职场文书
导游词之泉州崇武古城
2019/12/20 职场文书
Nginx快速入门教程
2021/03/31 Servers
【2·13】一图读懂中国无线电发展
2022/02/18 无线电