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 相关文章推荐
实现分十页分向前十页向后十页的处理
Oct 09 PHP
PHP中ADODB类详解
Mar 25 PHP
PHP mcrypt可逆加密算法分析
Jul 19 PHP
php遍历目录输出目录及其下的所有文件示例
Jan 27 PHP
PHP函数in_array()使用详解
Aug 20 PHP
php对关联数组循环遍历的实现方法
Mar 13 PHP
PHP安装threads多线程扩展基础教程
Nov 17 PHP
PHP代码维护,重构变困难的4种原因分析
Jan 25 PHP
PHP实现的简单分页类及用法示例
May 06 PHP
PHP面向对象程序设计之命名空间与自动加载类详解
Dec 02 PHP
PHP实现类似题库抽题效果
Aug 16 PHP
关于PHP5.6+版本“No input file specified”问题的解决
Dec 11 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入门速成教程
2007/03/19 PHP
IIS下PHP连接数据库提示mysql undefined function mysql_connect()
2010/06/04 PHP
PHP PDOStatement::rowCount讲解
2019/02/01 PHP
js文字滚动停顿效果代码
2008/06/28 Javascript
jQuery的学习步骤
2011/02/23 Javascript
jQuery EasyUI API 中文文档 搜索框
2011/09/29 Javascript
利用jQuery的deferred对象实现异步按顺序加载JS文件
2013/03/17 Javascript
基于JavaScript 声明全局变量的三种方式详解
2013/05/07 Javascript
JQuery性能优化的几点建议
2014/05/14 Javascript
JavaScript 七大技巧(二)
2015/12/13 Javascript
JavaScript和jQuery获取input框的绝对位置实现方法
2016/10/13 Javascript
详解Angular的双向数据绑定(MV-VM)
2016/12/26 Javascript
jQuery密码强度验证控件使用详解
2017/01/05 Javascript
原生js实现网页顶部自动下拉/收缩广告效果
2017/01/20 Javascript
如何用JS/HTML将时间戳转换为“xx天前”的形式
2017/02/06 Javascript
整理关于Bootstrap列表组的慕课笔记
2017/03/29 Javascript
JavaScript事件方法(实例讲解)
2017/06/27 Javascript
基于JS递归函数细化认识及实用实例(推荐)
2017/08/07 Javascript
新手vue构建单页面应用实例代码
2017/09/18 Javascript
浅谈Vue2.0父子组件间事件派发机制
2018/01/08 Javascript
vue中使用protobuf的过程记录
2018/10/26 Javascript
Vue利用History记录上一页面的数据方法实例
2018/11/02 Javascript
在vue中使用jsx语法的使用方法
2019/09/30 Javascript
jQuery实现雪花飘落效果
2020/08/02 jQuery
[02:39]我与DAC之Newbee.Moogy:从论坛到TI
2018/03/26 DOTA
详解python的webrtc库实现语音端点检测
2017/05/31 Python
Sanic框架Cookies操作示例
2018/07/17 Python
Python3和pyqt5实现控件数据动态显示方式
2019/12/13 Python
python脚本后台执行方式
2019/12/21 Python
Aquatalia官网:意大利著名鞋履品牌
2019/09/26 全球购物
Molton Brown美国官网:奢华美容、香水、沐浴和身体护理
2020/09/02 全球购物
EJB的激活机制
2013/10/25 面试题
Java面试题:Java类的Main方法如果是Private将会怎么样
2016/08/18 面试题
学习优秀共产党员先进事迹思想报告
2014/09/17 职场文书
公司岗位说明书
2015/10/08 职场文书
python中__slots__节约内存的具体做法
2021/07/04 Python