温故知新(5)——组合模式
2012-09-07 16:54
375 查看
概述
组合模式大概是每个人都用过的一种模式,或有心,或无意。因为如果要把一个一个的节点组合成“树”,组合模式的写法应该是比较自然的一种表达。但是个体与整体的访问一致性,可能需要特别注意一下。先看看GOF给出的模式意图。1、组合模式用来构建“部分-整体”的层次结构,也就是树;
2、客户端对象使用对象个体和对象的组合体时,方法相同。
组合模式的实现过程中有一些值得考虑的地方,下节将详述。
结构
下面是组合模式的类图:整理一下模式参与者(为了表述清楚,将使用树形结构的术语):
1、树节点的抽象,叶节点和非叶节点都要实现这个接口——IComposite;
2、叶节点,组合中最基础的单位——Leaf;
3、分支节点,可以包含其他分支节点或叶节点——Composite;
4、客户端代码——Client。
上图的IComposite的接口中,除定义了Operation这样一个公共的操作以外,还定义了Add、Remove的子对象的管理方法,这样当Leaf类实现这个接口时就必须实现这些对它来说没有意义的方法(因为叶子不包含子对象)。这虽然有些违反“类只能定义对它子类有意义的操作”这条设计原则,但是换来的是Client对Leaf和Composite使用的一致性。我们可以将上面的做法称为接口最大化,相反也可以采用接口最小化的做法,即IComposite只包含Operation方法,而将子对象的管理方法放入Composite中实现,这样Leaf将变得清晰,但是Client在使用Leaf和Composite就要区别对待。由于GOF的意图中强调了这种使用的一致性,因此本文将采用接口最大化的方法。但在实际使用中应该具体分析,在两种方法中做出取舍。
示例
金融研究机构经常针对当前的经济形势撰写研究报告,为了更好的管理这些报告,需要对这些报告进行分类。分类不仅限于一级,即分类下可以包含子分类,子分类下可以再包含子分类,由此构成了一个分类树,研究报告包含在叶子节点的分类中。需求要求选择任意一个分类节点(跟、分支、叶子),列出这个分类下所有的报告。下面的实现在把叶子节点称为分类Category,分支节点成为分类组。1、定义分类的接口ICategory。
usingSystem;
usingSystem.Collections.Generic;
namespaceDesignPatterns.Composite
{
///<summary>
///报告分类接口
///</summary>
publicinterfaceICategory
{
//分类名称
stringName{get;set;}
//获取分类下的报告
List<Report>GetReports();
//添加子分类
voidAddSubCategory(ICategorycategory);
//移除子分类
voidRemoveSubCategory(ICategorycategory);
//获取子分类
ICategoryGetSubCategory(intindex);
//子分类个数
intCount{get;}
}
}
.codearea{color:black;background-color:white;line-height:18px;border:1pxsolid#4f81bd;margin:0;width:auto!important;width:100%;overflow:auto;text-align:left;font-size:12px;font-family:"CourierNew","Consolas","Fixedsys","BitStreamVeraSansMono",courier,monospace,serif}
.codeareapre{color:black;line-height:18px;padding:00012px!important;margin:0em;background-color:#fff!important}
.linewrappre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;word-break:normal}
.codeareapre.alt{background-color:#f7f7ff!important}
.codearea.lnum{color:#4f81bd;line-height:18px}
2、实现分类Category。可以看到Category空实现了子分类的管理方法。
usingSystem;
usingSystem.Collections.Generic;
namespaceDesignPatterns.Composite
{
///<summary>
///具体分类
///</summary>
publicclassCategory:ICategory
{
publicCategory(stringname)
{
this.Name=name;
}
publicstringName{get;set;}
publicList<Report>GetReports()
{
returnnewList<Report>(){newReport(),newReport(),newReport()};
}
publicvoidAddSubCategory(ICategorycategory)
{
thrownewNotSupportedException("具体分类不支持此操作。");
}
publicvoidRemoveSubCategory(ICategorycategory)
{
thrownewNotSupportedException("具体分类不支持此操作。");
}
publicICategoryGetSubCategory(intindex)
{
thrownewNotSupportedException("具体分类不支持此操作。");
}
publicintCount
{
get{thrownewNotSupportedException("具体分类不支持此操作。");}
}
}
}
.codearea{color:black;background-color:white;line-height:18px;border:1pxsolid#4f81bd;margin:0;width:auto!important;width:100%;overflow:auto;text-align:left;font-size:12px;font-family:"CourierNew","Consolas","Fixedsys","BitStreamVeraSansMono",courier,monospace,serif}
.codeareapre{color:black;line-height:18px;padding:00012px!important;margin:0em;background-color:#fff!important}
.linewrappre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;word-break:normal}
.codeareapre.alt{background-color:#f7f7ff!important}
.codearea.lnum{color:#4f81bd;line-height:18px}
3、实现分类组CategoryGroup。
usingSystem;
usingSystem.Collections.Generic;
namespaceDesignPatterns.Composite
{
///<summary>
///分类组
///</summary>
publicclassCategoryGroup:ICategory
{
publicCategoryGroup(stringname)
{
this.Name=name;
this.subCategories=newList<ICategory>();
}
publicstringName{get;set;}
publicList<Report>GetReports()
{
List<Report>reports=newList<Report>();
foreach(varcinthis.subCategories)
{
reports.AddRange(c.GetReports());
}
returnreports;
}
privateList<ICategory>subCategories;
publicvoidAddSubCategory(ICategorycategory)
{
this.subCategories.Add(category);
}
publicvoidRemoveSubCategory(ICategorycategory)
{
this.subCategories.Remove(category);
}
publicICategoryGetSubCategory(intindex)
{
returnthis.subCategories[index];
}
publicintCount
{
get
{
returnthis.subCategories.Count;
}
}
}
}
.codearea{color:black;background-color:white;line-height:18px;border:1pxsolid#4f81bd;margin:0;width:auto!important;width:100%;overflow:auto;text-align:left;font-size:12px;font-family:"CourierNew","Consolas","Fixedsys","BitStreamVeraSansMono",courier,monospace,serif}
.codeareapre{color:black;line-height:18px;padding:00012px!important;margin:0em;background-color:#fff!important}
.linewrappre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;word-break:normal}
.codeareapre.alt{background-color:#f7f7ff!important}
.codearea.lnum{color:#4f81bd;line-height:18px}
4、添加一个表示报告的实体类Report。
usingSystem;
namespaceDesignPatterns.Composite
{
///<summary>
///报告实体类
///</summary>
publicclassReport
{
publicReport()
{
//每次生成GUID对象的hash码做种子,生成随机数
Randomr=newRandom(Guid.NewGuid().GetHashCode());
this.Id=r.Next(1,999999);
}
//报告ID
publicintId{get;set;}
}
}
.codearea{color:black;background-color:white;line-height:18px;border:1pxsolid#4f81bd;margin:0;width:auto!important;width:100%;overflow:auto;text-align:left;font-size:12px;font-family:"CourierNew","Consolas","Fixedsys","BitStreamVeraSansMono",courier,monospace,serif}
.codeareapre{color:black;line-height:18px;padding:00012px!important;margin:0em;background-color:#fff!important}
.linewrappre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;word-break:normal}
.codeareapre.alt{background-color:#f7f7ff!important}
.codearea.lnum{color:#4f81bd;line-height:18px}
5、客户端代码。
usingSystem;
namespaceDesignPatterns.Composite
{
classProgram
{
staticvoidMain(string[]args)
{
//组合过程
ICategoryroot=newCategoryGroup("全部报告");
ICategorymacro=newCategory("宏观研究");
ICategoryindustry=newCategoryGroup("行业研究");
ICategoryagriculture=newCategory("农业");
ICategoryfinance=newCategory("金融业");
industry.AddSubCategory(agriculture);
industry.AddSubCategory(finance);
root.AddSubCategory(macro);
root.AddSubCategory(industry);
//根节点、分支节点、叶节点的使用完成一致。
DisplayReports(root);
DisplayReports(industry);
DisplayReports(agriculture);
Console.WriteLine("按任意键结束...");
Console.ReadKey();
}
//输出
privatestaticvoidDisplayReports(ICategorycategory)
{
Console.WriteLine(category.Name+":");
foreach(varrincategory.GetReports())
{
Console.WriteLine(r.Id);
}
Console.WriteLine("===============================");
}
}
}
.codearea{color:black;background-color:white;line-height:18px;border:1pxsolid#4f81bd;margin:0;width:auto!important;width:100%;overflow:auto;text-align:left;font-size:12px;font-family:"CourierNew","Consolas","Fixedsys","BitStreamVeraSansMono",courier,monospace,serif}
.codeareapre{color:black;line-height:18px;padding:00012px!important;margin:0em;background-color:#fff!important}
.linewrappre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;word-break:normal}
.codeareapre.alt{background-color:#f7f7ff!important}
.codearea.lnum{color:#4f81bd;line-height:18px}
6、运行,查询结果。
博文(
相关文章推荐
- 组合模式
- 设计模式之组合模式
- 设计模式与泡mm的关系之Composite组合模式及组合模式的再思考
- 温故知新(3)——原型模式
- 十一.结构型设计模式——Composite Pattern(组合模式)
- (十九)组合模式详解
- 设计模式学习笔记——组合模式
- 来说说(Composite)组合模式
- 组合模式——公司组织结构
- android设计模式系列之组合模式
- 十五、组合模式
- Java设计模式透析之 —— 组合(Composite)
- GOF23设计模式之组合模式之实现
- 组合模式
- java 组合模式
- 设计模式C++实现 —— 外观模式、组合模式
- Javascript设计模式理论与实战:组合模式
- Composite 组合(结果型模式)笔记
- javascript组合使用构造函数模式和原型模式实例
- 设计模式----组合模式(C#)