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 echo 输出字符串函数详解
May 13 PHP
PHP支持多种格式图片上传(支持jpg、png、gif)
Nov 03 PHP
php中使用preg_replace函数匹配图片并加上链接的方法
Feb 06 PHP
PHP header()函数使用详细(301、404等错误设置)
Apr 17 PHP
一个简单且很好用的php分页类
Oct 26 PHP
PHP中字符安全过滤函数使用小结
Feb 25 PHP
php实现将任意进制数转换成10进制的方法
Apr 17 PHP
PHP中Http协议post请求参数
Nov 02 PHP
php计算多个集合的笛卡尔积实例详解
Feb 16 PHP
PHP中使用jQuery+Ajax实现分页查询多功能操作(示例讲解)
Sep 17 PHP
tp5(thinkPHP5框架)时间查询操作实例分析
May 29 PHP
在Laravel 的 Blade 模版中实现定义变量
Oct 14 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
颠覆常识!无色透明的咖啡诞生了(中日双语)
2021/03/03 咖啡文化
php excel reader读取excel内容存入数据库实现代码
2012/12/06 PHP
PHP CLI模式下的多进程应用分析
2013/06/03 PHP
PHP的curl实现get,post和cookie(实例介绍)
2013/06/17 PHP
js限制checkbox勾选的个数以及php获取多个checkbbox的方法深入解析
2013/07/18 PHP
一个漂亮的php验证码类(分享)
2013/08/06 PHP
30个php操作redis常用方法代码例子
2014/07/05 PHP
tp5框架无刷新分页实现方法分析
2019/09/26 PHP
精通JavaScript 纠正 cleanWhitespace函数
2010/03/11 Javascript
基于Jquery实现的一个图片滚动切换
2012/06/21 Javascript
解析页面加载与js函数的执行 onload or ready
2013/12/12 Javascript
js调试系列 断点与动态调试[基础篇]
2014/06/18 Javascript
jQuery实现的简洁下拉菜单导航效果代码
2015/08/26 Javascript
jquery实现的用户注册表单提示操作效果代码分享
2015/08/28 Javascript
jQuery检测滚动条是否到达底部
2015/12/15 Javascript
基于JavaScript实现移除(删除)数组中指定元素
2016/01/04 Javascript
原生js实现addClass,removeClass,hasClass方法
2016/04/27 Javascript
Node.js刷新session过期时间的实现方法推荐
2016/05/18 Javascript
javascript的函数劫持浅析
2016/09/26 Javascript
微信公众平台开发教程(六)获取个性二维码的实例
2016/12/02 Javascript
COM组件中调用JavaScript函数详解及实例
2017/02/23 Javascript
node.js实现回调的方法示例
2017/03/01 Javascript
Angular7创建项目、组件、服务以及服务的使用
2019/02/19 Javascript
小程序Scroll-view上拉滚动刷新数据
2020/06/21 Javascript
[38:31]完美世界DOTA2联赛PWL S3 Magma vs GXR 第一场 12.13
2020/12/17 DOTA
Python Web框架Tornado运行和部署
2020/10/19 Python
全面了解python中的类,对象,方法,属性
2016/09/11 Python
Windows平台Python连接sqlite3数据库的方法分析
2017/07/12 Python
python实现简易淘宝购物
2019/11/22 Python
Selenium启动Chrome时配置选项详解
2020/03/18 Python
解决windows上安装tensorflow时报错,“DLL load failed: 找不到指定的模块”的问题
2020/05/20 Python
解决Keras 中加入lambda层无法正常载入模型问题
2020/06/16 Python
利用CSS3的border-radius绘制太极及爱心图案示例
2016/05/17 HTML / CSS
Myprotein台湾官方网站:全球领先的运动营养品牌
2018/12/10 全球购物
《夏夜多美》教学反思
2014/02/17 职场文书
工作试用期自我评价
2015/03/10 职场文书