登录
注册
搜索
帮助
会员
界面
简洁版本
在线
bugsbox技术论坛
软件开发技术
设计模式
C#设计模式(11)-Composite Pattern
帖子标题
BugsBox原创
BugsBox C#代码生成器
电脑问题
联想Y430,450,G430闪屏信息收集
软件问题
综合问题
算法学习
数据结构
正则表达式
编程语言
F#
C#
VB.NET
JAVA
JavaScript
HTML/DHTML/XHTML
C&C++
软件开发技术
JSP
JSF
Asp.net
J2ME
Windows Form
Asp
Web 2.0
JavaScript高级技术
文档技术
建模工具
设计模式
php
数据库
Sql Server
Access
Oracle
MySql
其他交流
论坛意见
闲聊人生
无厘灌水
1
/ 1 页
1
跳转
页
查看:
356
C#设计模式(11)-Composite Pattern
hutaoshu
hutaoshu
组别:
管理员
性别:
来自:
积分:
197
帖子:
192
注册:
2009-03-31
2009-07-16 11:24
|
只看楼主
树型
|
收藏
|
小
中
大
1
C#设计模式(11)-Composite Pattern
一、 合成(Composite)模式合成模式有时又叫做部分-整体模式(Part-Whole)。合成模式将对象组织到树结构中,可以用来描述整体与部分的关系。合成模式可以使客户端将单纯元素与复合元素同等看待。
从和尚的故事谈起
这是小时候我奶奶讲的故事:从前有个山,山里有个庙,庙里有个老和尚在给小和尚讲故事,讲的什么故事呢?从前有个山,山里有个庙……。奶奶的故事要循环多少次,根据你多长时间睡着而定。在故事中有山、有庙、有和尚、有故事。因此,故事的角色有两种:一种里面没有其它角色;另一种内部有其它角色。
对象的树结构
一个树结构由两种节点组成:树枝节点和树叶节点。树枝节点可以有子节点,而一个树叶节点不可以有子节点。除了根节点外,其它节点有且只有一个父节点。
注意:一个树枝节点可以不带任何叶子,但是它因为有带叶子的能力,因此仍然是树枝节点,而不会成为叶节点。一个树叶节点永远不可能带有子节点。
二、 合成模式概述下图所示的类图省略了各个角色的细节。
可以看出,上面的类图结构涉及到三个角色:
抽象构件(Component)角色:
这是一个抽象角色,它给参与组合的对象规定一个接口。这个角色给出共有接口及其默认行为。
树叶构件(Leaf)角色:
代表参加组合的树叶对象。一个树叶对象没有下级子对象。
树枝构件(Composite)角色:
代表参加组合的有子对象的对象,并给出树枝构件对象的行为。
可以看出,Composite类型的对象可以包含其它Component类型的对象。换而言之,Composite类型对象可以含有其它的树枝(Composite)类型或树叶(Leaf)类型的对象。
合成模式的实现根据所实现接口的区别分为两种形式,分别称为安全模式和透明模式。合成模式可以不提供父对象的管理方法,但合成模式必须在合适的地方提供子对象的管理方法(诸如:add、remove、getChild等)。
透明方式
作为第一种选择,在Component里面声明所有的用来管理子类对象的方法,包括add()、remove(),以及getChild()方法。这样做的好处是所有的构件类都有相同的接口。在客户端看来,树叶类对象与合成类对象的区别起码在接口层次上消失了,客户端可以同等同的对待所有的对象。这就是透明形式的合成模式。
这个选择的缺点是不够安全,因为树叶类对象和合成类对象在本质上是有区别的。树叶类对象不可能有下一个层次的对象,因此add()、remove()以及getChild()方法没有意义,是在编译时期不会出错,而只会在运行时期才会出错。
安全方式
第二种选择是在Composite类里面声明所有的用来管理子类对象的方法。这样的做法是安全的做法,因为树叶类型的对象根本就没有管理子类对象的方法,因此,如果客户端对树叶类对象使用这些方法时,程序会在编译时期出错。
这个选择的缺点是不够透明,因为树叶类和合成类将具有不同的接口。
这两个形式各有优缺点,需要根据软件的具体情况做出取舍决定。
三、 安全式的合成模式的结构安全式的合成模式要求管理聚集的方法只出现在树枝构件类中,而不出现在树叶构件中。
这种形式涉及到三个角色:
抽象构件(Component)角色:
这是一个抽象角色,它给参加组合的对象定义出公共的接口及其默认行为,可以用来管理所有的子对象。在安全式的合成模式里,构件角色并不是定义出管理子对象的方法,这一定义由树枝构件对象给出。
树叶构件(Leaf)角色:
树叶对象是没有下级子对象的对象,定义出参加组合的原始对象的行为。
树枝构件(Composite)角色:
代表参加组合的有下级子对象的对象。树枝对象给出所有的管理子对象的方法,如add()、remove()、getChild()等。
四、 安全式的合成模式实现以下示例性代码演示了安全式的合成模式代码:
//
Composite pattern -- Structural example
using
System;
using
System.Text;
using
System.Collections;
//
"Component"
abstract
class
Component
{
//
Fields
protected
string
name;
//
Constructors
public
Component(
string
name )
{
this
.name
=
name;
}
//
Operation
public
abstract
void
Display(
int
depth );
}
//
"Composite"
class
Composite : Component
{
//
Fields
private
ArrayList children
=
new
ArrayList();
//
Constructors
public
Composite(
string
name ) :
base
( name )
{}
//
Methods
public
void
Add( Component component )
{
children.Add( component );
}
public
void
Remove( Component component )
{
children.Remove( component );
}
public
override
void
Display(
int
depth )
{
Console.WriteLine(
new
String(
'
-
'
, depth )
+
name );
//
Display each of the node's children
foreach
( Component component
in
children )
component.Display( depth
+
2
);
}
}
//
"Leaf"
class
Leaf : Component
{
//
Constructors
public
Leaf(
string
name ) :
base
( name )
{}
//
Methods
public
override
void
Display(
int
depth )
{
Console.WriteLine(
new
String(
'
-
'
, depth )
+
name );
}
}
/**/
///
<summary>
///
Client test
///
</summary>
public
class
Client
{
public
static
void
Main(
string
[] args )
{
//
Create a tree structure
Composite root
=
new
Composite(
"
root
"
);
root.Add(
new
Leaf(
"
Leaf A
"
));
root.Add(
new
Leaf(
"
Leaf B
"
));
Composite comp
=
new
Composite(
"
Composite X
"
);
comp.Add(
new
Leaf(
"
Leaf XA
"
) );
comp.Add(
new
Leaf(
"
Leaf XB
"
) );
root.Add( comp );
root.Add(
new
Leaf(
"
Leaf C
"
));
//
Add and remove a leaf
Leaf l
=
new
Leaf(
"
Leaf D
"
);
root.Add( l );
root.Remove( l );
//
Recursively display nodes
root.Display(
1
);
}
}
五、 透明式的合成模式结构与安全式的合成模式不同的是,透明式的合成模式要求所有的具体构件类,不论树枝构件还是树叶构件,均符合一个固定的接口。
这种形式涉及到三个角色:
抽象构件(Component)角色:
这是一个抽象角色,它给参加组合的对象规定一个接口,规范共有的接口及默认行为。
树叶构件(Leaf)角色:
代表参加组合的树叶对象,定义出参加组合的原始对象的行为。树叶类会给出add()、remove()以及getChild()之类的用来管理子类对对象的方法的平庸实现。
树枝构件(Composite)角色:
代表参加组合的有子对象的对象,定义出这样的对象的行为。
六、 透明式的合成模式实现以下示例性代码演示了安全式的合成模式代码:
//
Composite pattern -- Structural example
using
System;
using
System.Text;
using
System.Collections;
//
"Component"
abstract
class
Component
{
//
Fields
protected
string
name;
//
Constructors
public
Component(
string
name )
{
this
.name
=
name; }
//
Methods
abstract
public
void
Add(Component c);
abstract
public
void
Remove( Component c );
abstract
public
void
Display(
int
depth );
}
//
"Composite"
class
Composite : Component
{
//
Fields
private
ArrayList children
=
new
ArrayList();
//
Constructors
public
Composite(
string
name ) :
base
( name )
{}
//
Methods
public
override
void
Add( Component component )
{ children.Add( component ); }
public
override
void
Remove( Component component )
{ children.Remove( component ); }
public
override
void
Display(
int
depth )
{
Console.WriteLine(
new
String(
'
-
'
, depth )
+
name );
//
Display each of the node's children
foreach
( Component component
in
children )
component.Display( depth
+
2
);
}
}
//
"Leaf"
class
Leaf : Component
{
//
Constructors
public
Leaf(
string
name ) :
base
( name )
{}
//
Methods
public
override
void
Add( Component c )
{ Console.WriteLine(
"
Cannot add to a leaf
"
); }
public
override
void
Remove( Component c )
{ Console.WriteLine(
"
Cannot remove from a leaf
"
); }
public
override
void
Display(
int
depth )
{ Console.WriteLine(
new
String(
'
-
'
, depth )
+
name ); }
}
/**/
///
<summary>
///
Client test
///
</summary>
public
class
Client
{
public
static
void
Main(
string
[] args )
{
//
Create a tree structure
Composite root
=
new
Composite(
"
root
"
);
root.Add(
new
Leaf(
"
Leaf A
"
));
root.Add(
new
Leaf(
"
Leaf B
"
));
Composite comp
=
new
Composite(
"
Composite X
"
);
comp.Add(
new
Leaf(
"
Leaf XA
"
) );
comp.Add(
new
Leaf(
"
Leaf XB
"
) );
root.Add( comp );
root.Add(
new
Leaf(
"
Leaf C
"
));
//
Add and remove a leaf
Leaf l
=
new
Leaf(
"
Leaf D
"
);
root.Add( l );
root.Remove( l );
//
Recursively display nodes
root.Display(
1
);
}
}
七、 使用合成模式时考虑的几个问题
明显的给出父对象的引用。在子对象里面给出父对象的引用,可以很容易的遍历所有父对象。有了这个引用,可以方便的应用责任链模式。
在通常的系统里,可以使用享元模式实现构件的共享,但是由于合成模式的对象经常要有对父对象的引用,因此共享不容易实现。
有时候系统需要遍历一个树枝结构的子构件很多次,这时候可以考虑把遍历子构件的结果暂时存储在父构件里面作为缓存。
关于使用什么数据类型来存储子对象的问题,在示意性的代码中使用了ArrayList,在实际系统中可以使用其它聚集或数组等。
客户端尽量不要直接调用树叶类中的方法,而是借助其父类(Component)的多态性完成调用,这样可以增加代码的复用性。
八、 和尚的故事
九、 一个实际应用Composite模式的例子下面是一个实际应用中的程序,演示了通过一些基本图像元素(直线、园等)以及一些复合图像元素(由基本图像元素组合而成)构建复杂的图形树的过程。
//
Composite pattern -- Real World example
using
System;
using
System.Collections;
//
"Component"
abstract
class
DrawingElement
{
//
Fields
protected
string
name;
//
Constructors
public
DrawingElement(
string
name )
{
this
.name
=
name; }
//
Operation
abstract
public
void
Display(
int
indent );
}
//
"Leaf"
class
PrimitiveElement : DrawingElement
{
//
Constructors
public
PrimitiveElement(
string
name ) :
base
( name )
{}
//
Operation
public
override
void
Display(
int
indent )
{
Console.WriteLine(
new
String(
'
-
'
, indent )
+
"
draw a {0}
"
, name );
}
}
//
"Composite"
class
CompositeElement : DrawingElement
{
//
Fields
private
ArrayList elements
=
new
ArrayList();
//
Constructors
public
CompositeElement(
string
name ) :
base
( name )
{}
//
Methods
public
void
Add( DrawingElement d )
{ elements.Add( d ); }
public
void
Remove( DrawingElement d )
{ elements.Remove( d ); }
public
override
void
Display(
int
indent )
{
Console.WriteLine(
new
String(
'
-
'
, indent )
+
"
+
"
+
name );
//
Display each child element on this node
foreach
( DrawingElement c
in
elements )
c.Display( indent
+
2
);
}
}
/**/
///
<summary>
///
CompositeApp test
///
</summary>
public
class
CompositeApp
{
public
static
void
Main(
string
[] args )
{
//
Create a tree structure
CompositeElement root
=
new
CompositeElement(
"
Picture
"
);
root.Add(
new
PrimitiveElement(
"
Red Line
"
));
root.Add(
new
PrimitiveElement(
"
Blue Circle
"
));
root.Add(
new
PrimitiveElement(
"
Green Box
"
));
CompositeElement comp
=
new
CompositeElement(
"
Two Circles
"
);
comp.Add(
new
PrimitiveElement(
"
Black Circle
"
) );
comp.Add(
new
PrimitiveElement(
"
White Circle
"
) );
root.Add( comp );
//
Add and remove a PrimitiveElement
PrimitiveElement l
=
new
PrimitiveElement(
"
Yellow Line
"
);
root.Add( l );
root.Remove( l );
//
Recursively display nodes
root.Display(
1
);
}
}
合成模式与很多其它模式都有联系,将在后续内容中逐步介绍。
参考文献:
阎宏,《Java与模式》,电子工业出版社
[美]James W. Cooper,《C#设计模式》,电子工业出版社
[美]Alan Shalloway James R. Trott,《Design Patterns Explained》,中国电力出版社
[美]Robert C. Martin,《敏捷软件开发-原则、模式与实践》,清华大学出版社
[美]Don Box, Chris Sells,《.NET本质论 第1卷:公共语言运行库》,中国电力出版社
0
0
0
(请您对文章做出评价)
发送短消息
查看公共资料
查找该会员全部帖子
UID:
3
精华:
1
威望:
0
金钱:
40.05 元
状态:
离线
<<
上一主题
|
下一主题
>>
1
/ 1 页
1
跳转
页
论坛跳转...
BugsBox原创
BugsBox C#代码生成器
电脑问题
联想Y430,450,G430闪屏信息收集
软件问题
综合问题
算法学习
数据结构
正则表达式
编程语言
F#
F#语言基础
F#编程指南
C#
C# 参考
C# 编程指南
Linq专题
VB.NET
JAVA
JavaScript
HTML/DHTML/XHTML
C&C++
软件开发技术
JSP
SSH
JSF
sun-ri
myfaces
icefaces
richfaces
seam
Asp.net
asp.net控件开发
J2ME
Windows Form
WinForm控件开发
Asp
Web 2.0
JavaScript高级技术
Ajax
ext
jquery
prototype
文档技术
建模工具
设计模式
php
数据库
Sql Server
Access
Oracle
MySql
其他交流
论坛意见
闲聊人生
无厘灌水
我的主题
我的帖子
我的精华
帖子标题
空间日志
相册标题
作 者