Composite模式涉及的是一组对象,其中有些对象可能含有其他的对象;因此,有些对象可能代表一个对象群组,而其他的则是单个对象,即叶子。利用Composite模式建模包含两个重要的建模概念。其中一个重要的思想是所设计的群组即能包含单个个体,还要能包含其他群组(一个常见的错误是所设计的群组只能包含叶子)。另一个重要的概念是要定义出单个对象和对象组合的公共特性。结合这两个概念,我们可以定义即适合群组又适合单个个体的通用类型,然后将群组建模成具有这种类型的对象的集合。
Composite模式的设计意图在于:让用户能够用统一的接口处理单个对象以及对象组合。
1. 常见的组合:
下图给出了常见的Composite模式的结构。Component类抽象出了Leaf类和Composite类共享的公共接口。Comsposite类又包含其他的Composite对象以及Leaf对象。
图5-1 Composite模式的核心思想是组合类对象可以包含其他组合类的对象
(而且Composite类和Leaf类共享公共的接口)
注意:上图所示的Component类是一个抽象类,不含有具体的操作,因而我们可以把它定义为接口,然后再由Leaf类和Composite类来实现这个接口。
2. 上图所示的Composite类维护Component对象集合,而不是简单的叶集合,原因如下:
设计Composite类来维护Component对象集合,这种做法让Composite对象拥有Leaf对象或者其他Composite对象。换句话说,这种设计思路允许我们把组模拟成其他组的集合。比如,我们也许希望把用户系统权限定位为特定权限或者其他权限组的集合。再举个例子,我们也许希望把某工作定义为过程步骤和其他过程的集合。相对于把组合结构定义为叶对象集合,这种定义方式更加灵活。如果只允许使用叶对象的集合,则我们的“组合结构”只有一层。
3. Composite模式的递归特性:
某公司由多个车间组成,每个车间有一条或者多条生产线,一条生产线上有许多机器,它们相互合作完成生产任务以保证生产进度。目前,该公司的开发者按照以下类图将工厂、车间、生产线看成为组合“机器”,完成了对该问题的建模。
图5-2 getMachineCount()方法即适合于单台机器也适合于机器组合
4.组合、树和环:
在组合结构中,我们将含有其他节点引用的节点称作树(tree)。描述对象模型的图应该是有向图:因为对象引用是有方向的。图论中的树通常是无向图。不过,有向图也可以被称作树,只要满足下列条件:
(1)它有一个不被引用的根节点;
(2)其他每个节点都绝对仅有一个引用该节点的父节点。
下图给出了plant工厂的对象模型。plant是MachineComposite类的对象。这个工厂包含一个车间,该车间里有三台机器:mixer、press和assembler。在该对象模型中,plant对象中的机器列表含有对机器mixer的直接引用。
图5-3 对象模型形成的即非环又非树的图
上图的对象模型并不包含环,但由于有两个对象引用了相同的mixer对象,所以它不是树。
假设Composite模式是树状结构,并且你的系统允许使用都不是树的Composite模式,那么作用在组合对象上的方法可能是有问题的。前面的UML读中有定义getMachineCount(),在针对该问题的解答中,Machine类对该方法的实现可证明是正确的:
public int getMachineCount()
{
return 1;
}
MachineComposite类也正确地实现了getMachineCount()方法,返回组合对象中每个组成部分的机器数目之和。
public int getMachineCount()
{
int count = 0;
Iterator i = components.iterator();
while(i.hasNext())
{
MachineComponent mc = (MachineComponent)i.next();
count += mc.getMachineCount();
}
return count;
}
只要MachineComponent对象模型为树状结构,那么上面的这些方法就是正确的。但是曾经被认为是树状结构的某个组合对象模型可能会突然不再是树状结构,尤其是在用户能够编辑该组合对象模型的时候,这种情况就更容易出现。下面我们考虑会发生在Oozinoz公司的一个例子。
该焰火公司的工程师利用GUI应用程序来记录和更新工厂里的机器组合对象模型。有一天,他们报告称工厂里的机器数量有误。你可以通过OozinozFactory类中的plant()方法重新创建它们的对象模型:
public static MachineComposite plant()
{
MachineComposite plant = new MachineComposite(100);
MachineComposite bay = new MachineComposite(101);
Machine mixer = new Mixer(102);
Machine press = new StarPress(103);
Machine assembler = new ShellAssembler(104);
bay.add(mixer);
bay.add(press);
bay.add(assembler);
plant.add(mixer);
plant.add(bay);
return plant;
}
图5-3中的plant对象就是由这段代码创建的。
5. 请问下面这段程序代码的输出是什么?
package app.composite;
import com.oozinoz.machine.*;
public class ShowPlant
{
public static void main(String[] args)
{
MachineComponent c = OozinozFactory.plant();
System.out.println("Number of machines:" + c.getMachineCount());
}
}
该程序的输出结果为:number of machines:4
实际上,plant工厂仅包含三台机器,但plant和bay对象都会对机器mixer统计一次,因为这两个对象都包含引用mixer的机器组件列表。
下面的情况会更糟:比如,某个工程师将plant对象作为一个组件加入到bay组合结构的列表中,这个时间调用getMachineCount()方法将会导致死循环。
Oozinoz公司的工程师通常使用这个GUI应用程序对工厂里的机器进行对象建模。该应用程序在添加一个节点的时候应该检查一下它是否已经在树状组件对象中。一个简单的实现方式是维护一个已存在的节点列表。然而,我们可能无法控制组合对象模型的构成方式。在这种情况下,我们可以写一个isTree()方法来检查组合对象模型是否为树状结构。
如果在遍历对象模型的各个引用时不会重复遇到同一个节点两次,那么该对象模型就为树状结构。我们可以在抽象类MachineComponent中实现isTree()方法,这样就可以在该方法中维护已访问过的节点列表。MachineComponent类可以将带参数的isTree(set:Set)方法作为抽象方法。图5-4给出了isTree()方法的实现层次。
MachineComponent类委托isTree()调用了其抽象的isTree(s:Set)方法:
public boolean isTree()
{
return isTree(new HashSet());
}
protected abstract boolean isTree(Set s);
图5-4 isTree()方法检测组合对象模型是否为树状结构
Machine类以及MachineComposite类必须实现isTree(s:Set)抽象方法。对于Machine类来说,isTree()的实现非常简单,这反映出每台机器都是树状结构:
protected boolean isTree(Set visited)
{
visited.add(this);
return true;
}
MachineComposite类中isTree()方法的实现方式如下:将调用它的对象加入已访问节点列表,然后迭代调用该组合对象的各个组件的isTree()方法。如果某个组件已被访问过,或如果某个组件本身不是树状结构,则该方法返回false;否则该方法返回true。
protected boolean isTree(Set visited)
{
visited.add(this);
Iterator i = components.iterator();
while(i.hadNext())
{
MachineComponent c = (MachineComponent)i.next();
if(visited.contains(c) || !c.isTree(visited))
return false;
}
return true;
}
只要多加小心,我们可以拒绝那些会让isTree()方法返回false的修改,从而保证对象模型为树状结构。不过在有些情况下,我们可能需要允许组合对象模型为非树状结构,特别是当正在建模的问题域含有环的时候。
- 大小: 2.7 KB
- 大小: 3.4 KB
- 大小: 3.3 KB
- 大小: 4.4 KB
分享到:
相关推荐
### C#面向对象设计模式纵横谈之Composite组合模式解析 #### 标题解析与核心概念 标题中的“C#面向对象设计模式纵横谈(9):Composite组合模式(结构型模式)”明确了文章的主题聚焦于C#语言环境下的设计模式探讨,...
在这里与各位分享本人从网络上下载的C#面向对象设计模式纵横谈系列视频,共有25节,除了第一节需要各位贡献一点资源分以作为对本人上传资源的回馈,后面的其他资源均不需要... 这是第9节:结构型模式Composite组合模式
组合模式是一种结构型设计模式,它允许我们创建部分-整体层次结构,使得部分与整体具有相同的行为。在C#中,这种模式可以帮助我们构建复杂的树形结构,使得客户端代码可以一致地处理单个对象和对象集合。让我们深入...
组合模式是一种行为设计模式,属于面向对象设计中的结构型模式,其主要目的是为了建立一种对象树形结构,这种结构能够使客户端代码以统一的方式处理单个对象和对象的组合。在组合模式中,我们通常会定义一个基类,...
**组合模式(Composite Pattern)详解** 组合模式是一种结构型设计模式,它将对象组织成树形结构,使得用户可以对单个对象和对象集合进行统一操作。这种模式在处理部分与整体关系时非常有用,允许我们一致地处理...
组合模式是一种结构型设计模式,它允许我们使用树形结构来表示部分-整体关系,使得我们能够以统一的方式处理单个对象和对象集合。在C++中,组合模式的应用可以帮助我们构建灵活且易于操作的对象层次结构,使得客户端...
23种Python设计模式示例演示源码包,比如包括了工厂模式、Bridge桥接模式、Builder构建模式、Facade外观模式、Adapter适配器模式,Composite组合模式、Decorator装饰器模式,FactoryMethod工厂方法模式、Flyweight享...
**组合模式**(Composite Pattern)是一种常用的结构型设计模式,主要用于构建具有层次结构的对象系统。它允许客户端以一致的方式处理单个对象和组合对象,简化了高层模块的调用。通过组合模式,可以将多个对象组织成...
组合模式(Composite Pattern)是一种树形结构的设计模式,它将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户可以对单个对象和组合对象进行一致性的操作处理,即客户程序可以像操作单个对象...
组合模式(Composite Pattern)是一种结构型设计模式,用于将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得客户端可以以统一的方式对待单个对象和组合对象,这种模式常用于需要处理树形结构的数据...
组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的...
**复合模式(Composite Pattern)**是一种结构型设计模式,它允许我们构建复杂的对象结构,并能像操作单个对象一样处理整个结构。在计算机科学中,这种模式尤其适用于表示部分-整体层次结构,使得用户可以一致地处理...
C#面向对象设计模式纵横谈(9):Composite 组合模式(结构型模式) C#面向对象设计模式纵横谈(10):Decorator 装饰模式(结构型模式) C#面向对象设计模式纵横谈(11):Facade 外观模式(结构型模式) C#面向对象设计...
组合模式(Composite Pattern)是一种结构型设计模式,它允许你将对象组合成树形结构以表示“部分-整体”的层次结构。这种模式使得客户端可以统一对待单个对象和对象组合。在组合模式中,有两种基本类型的对象:叶...
组合模式是一种对象结构型设计模式,它允许我们以树形结构来表示部分-整体关系,使得我们可以像处理单个对象一样处理整个集合。在五子棋游戏的实现中,组合模式的应用尤为关键,因为它帮助我们将棋盘上的棋子和棋盘...
组合模式(Composite Pattern)是一种对象结构型模式,其定义是将多个对象组合成树形结构以表示“整体-部分”关系的层次结构。它使得客户端对单个对象和组合对象的使用具有一致性。在组合模式中,对象被组织成树形...
组合模式(Composite Pattern)是一种结构型设计模式,它允许用户将对象组合成树形结构来表示部分-整体层次结构。该模式使得用户对单个对象和组合对象的使用具有一致性。 #### 实验内容 实验内容主要包括设计和实现...
**设计模式面面观:组合模式(Composite Pattern)** 组合模式是软件工程中的一种结构型设计模式,它允许我们以树形结构来表示部分与整体的关系,使得客户端代码可以一致地处理单个对象和对象组合。在组合模式中,...