设计模式(七)组合模式Composite(结构型)

设计模式(七)组合模式Composite(结构型)

1. 概述

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

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

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

2.问题

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

3.   解决方案

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

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

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

4.  组合模式的分类

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

5. 适用性

以下情况下适用Composite模式

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

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

6.
结构


典型的C
o m p o s i t e对象结构如下图所示:

7. 构建模式的组成

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

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

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

8. 效果

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

9. 实现

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

[php] view
plain
 copy

 print?

  1. <?php   
  2. /** 
  3.  * 组合模式  
  4.  *  
  5.  * @author guisu 
  6.  * @version  1.0 
  7.  * 组合模式:树形菜单 
  8.  *  
  9.  * 将对象组合成树形结构以表示"部分-整体"的层次结构,使得客户对单个对象和复合对象的使用具有一致性  
  10.  */   
  11. /** 
  12.  * 抽象构件角色(component) 
  13.  * 
  14.  */  
  15. abstract class MenuComponent  
  16. {  
  17.     public function add($component){}  
  18.     public function remove($component){}  
  19.     public function getName(){}  
  20.     public function getUrl(){}  
  21.     public function displayOperation(){}  
  22. }  
  23. /** 
  24.  * 树枝构件角色(Composite) 
  25.  * 
  26.  */  
  27. class MenuComposite extends MenuComponent  
  28. {  
  29.     private $_items = array();  
  30.     private $_name = null;  
  31.     private $_align = '';  
  32.     public function __construct($name) {  
  33.         $this->_name = $name;  
  34.     }  
  35.     public function add($component) {  
  36.         $this->_items[$component->getName()] = $component;  
  37.     }  
  38.     public function remove($component) {  
  39.         $key = array_search($component,$this->_items);  
  40.         if($key !== false) unset($this->_items[$key]);  
  41.     }  
  42.     public function getItems() {  
  43.         return $this->_items;  
  44.     }  
  45.       
  46.     public function displayOperation() {  
  47.         static $align = '|';  
  48.         if($this->getItems()) {  
  49.             //substr($align, strpos($align,));  
  50.             $align .= ' _ _ ';  
  51.         }else{  
  52.             $align .='';  
  53.         }  
  54.         echo $this->_name, " <br/>";  
  55.         foreach($this->_items as $name=> $item) {  
  56.             echo $align;  
  57.             $item->displayOperation();  
  58.         }  
  59.     }  
  60.   
  61.     public function getName(){  
  62.         return $this->_name;  
  63.     }  
  64. }  
  65.   
  66. /** 
  67.  *树叶构件角色(Leaf) 
  68.  * 
  69.  */  
  70. class ItemLeaf extends MenuComponent  
  71. {  
  72.     private $_name = null;  
  73.     private $_url = null;  
  74.     //public  $_align = '----';  
  75.     public function __construct($name,$url)  
  76.     {  
  77.         $this->_name = $name;  
  78.         $this->_url = $url;  
  79.     }  
  80.   
  81.     public function displayOperation()  
  82.     {  
  83.         echo '<a href="', $this->_url, '">' , $this->_name, '</a><br/>';  
  84.     }  
  85.   
  86.     public function getName(){  
  87.         return $this->_name;  
  88.     }  
  89. }  
  90.   
  91. class Client  
  92. {  
  93.     public static function displayMenu()  
  94.     {  
  95.         $subMenu1 = new MenuComposite("submenu1");  
  96.         $subMenu2 = new MenuComposite("submenu2");  
  97.         $subMenu3 = new MenuComposite("submenu3");  
  98.           
  99.         $subMenu4 = new MenuComposite("submenu4");  
  100.         $subMenu5 = new MenuComposite("submenu5");  
  101.         /* 
  102.         $item1 = new ItemLeaf("sohu","www.163.com"); 
  103.         $item2 = new ItemLeaf("sina","www.sina.com"); 
  104.          
  105.         $subMenu4 = new MenuComposite("submenu4"); 
  106.         $subMenu1->add($subMenu4); 
  107.          
  108.         $subMenu4->add($item1); 
  109.         $subMenu4->add($item2); 
  110.         */  
  111.         $item3 = new ItemLeaf("baidu","www.baidu.com");  
  112.         $item4 = new ItemLeaf("google","www.google.com");  
  113.         $subMenu2->add($item3);  
  114.         $subMenu2->add($item4);  
  115.           
  116.         $allMenu = new MenuComposite("AllMenu");  
  117.         $allMenu->add($subMenu1);  
  118.         $allMenu->add($subMenu2);  
  119.         $allMenu->add($subMenu3);  
  120.         $subMenu3->add($subMenu4);  
  121.         $subMenu4->add($subMenu5);  
  122.         $allMenu->displayOperation();  
  123.     }  
  124. }  
  125.   
  126. // 创建menu  
  127. Client::displayMenu();  
  128. ?>  

 

 

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

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

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

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

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

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

11. 总结

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

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

时间: 2024-09-12 15:00:44

设计模式(七)组合模式Composite(结构型)的相关文章

乐在其中设计模式(C#) - 组合模式(Composite Pattern)

原文:乐在其中设计模式(C#) - 组合模式(Composite Pattern)[索引页][源码下载] 乐在其中设计模式(C#) - 组合模式(Composite Pattern) 作者:webabcd 介绍 将对象组合成树形结构以表示"部分-整体"的层次结构.它使得客户对单个对象和复合对象的使用具有一致性. 示例 有一个Message实体类,使其单个对象和复合对象具有一致性. MessageModel using System;using System.Collections.Ge

【设计模式】—— 组合模式Composite

模式意图 使对象组合成树形的结构.使用户对单个对象和组合对象的使用具有一致性. 应用场景 1 表示对象的 部分-整体 层次结构 2 忽略组合对象与单个对象的不同,统一的使用组合结构中的所有对象. 模式结构 [安全的组合模式] 这种组合模式,叶子节点,也就是单个对象不具有对象的控制功能.仅仅有简单的业务操作. 1 package com.xingoo.composite.safe; 2 3 import java.util.ArrayList; 4 import java.util.List; 5

温故而知新:设计模式之组合模式(Composite)

场景: 如果想模拟windows的开始菜单,分析一下会发现里面的菜单项:有些有子菜单,有些则没有:因此大体可以将菜单类分为二类,设计代码如下:   /// <summary> /// 菜单的显示接口 /// </summary> public interface IMenu { void Show(); } /// <summary> /// 菜单基类 /// </summary> public class MenuBase { public string

.NET设计模式(15):结构型模式专题总结

主要内容 1.结构型模式概述 2.结构型模式区别与比较 3.对变化的封装 结构型模式概述 结构型模式,顾名思义讨论的是类和对象的结构,它采用继承机制来组合接口或实现(类结构型模式),或者通过组合一些对象,从而实现新的功能(对象结构型模式).这些结构型模式,它们在某些方面具有很大的相似性,仔细推敲,侧重点却各有不同. Adapter模式通过类的继承或者对象的组合侧重于转换已有的接口:Bridge模式通过将抽象和实现相分离,让它们可以分别独立的变化,它强调的是系统沿着多个方向的变化:Decorato

C#设计模式(10)——组合模式(Composite Pattern)

原文:C#设计模式(10)--组合模式(Composite Pattern) 一.引言 在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象和复合对象在功能上区别,导致在操作过程中必须区分简单对象和复合对象,这样就会导致客户调用带来不必要的麻烦,然而作为客户,它们希望能够始终一致地对待简单对象和复合对象.然而组合模式就是解决这样的问题.下面让我们看看组合模式是

设计模式:组合模式(Composite)

将对象组合成属性结构以表示"部分-整体"的层次结构.组合使得用户和单个对象和组合对象的使用具有一致性. 组合模式设计的角色: 1. Component:是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为.声明一个接口用于访问和管理Component. 2. Leaf:在组合中表示叶子节点对象,叶子节点没有子节点. 3. Composite:定义树枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加和删除等. 举个简单例子(树枝和叶子) 1

设计模式——11组合模式(Composite)

11.组合模式(Composite)组合模式有时又叫部分-整体模式在处理类似树形结构的问题时比较方便. 直接来看代码:[java] view plaincopy public class TreeNode { private String name; private TreeNode parent; private Vector children = new Vector(); public TreeNode(String name){ this.name = name; } public St

C++设计模式之组合模式_C 语言

问题描述 上图,是一个公司的组织结构图,总部下面有多个子公司,同时总部也有各个部门,子公司下面有多个部门.如果对这样的公司开发一个OA系统,作为程序员的你,如何设计这个OA系统呢?先不说如何设计实现,接着往下看,看完了下面的内容,再回过头来想怎么设计这样的OA系统. 什么是组合模式? 在GOF的<设计模式:可复用面向对象软件的基础>一书中对组合模式是这样说的:将对象组合成树形结构以表示"部分-整体"的层次结构.组合(Composite)模式使得用户对单个对象和组合对象的使用

iOS设计模式之组合模式

组合模式(Composite) 基本理解 整体和部分可以一直对待. 组合模式:将对象组合成树形结构以表示"部分--整体"的层次结构.组合模式使得用户对单个对象和组合独享的使用具有一致性. 透明方式和安全方式 透明方式:在Component(为组合中的对象声明接口)中声明所有用来管理子对象的方法 .这样实现该接口的子类都具有了该接口中的方法.这样的好处就是叶节点和枝节点对于外界没有区别,他们具有完全一致的行为接口.但问题也很明显,因为Leaf类本身不具备添加删除方法的功能,所以实现它是没