设计模式---数据结构模式之组合模式(Composite)
前提:数据结构模式
常常有一些组建在内部具有特定的数据结构,如果让客户程序依赖这些特定的数据结构,将极大的破坏组件的复用。这时候,将这些数据结构封装在内部,在外部提供统一的接口,来实现与特定数据结构无关的访问,是一种行之有效的解决方案。
典型模式
组合模式:Composite
迭代器模式:Iterator
责任链模式:Chain of Responsibility
一:组合模式
(一)概念
通过递归手段来构造树形对象结构并可以通过一个对象来访问整个对象
(二)动机
软件在某些情况下,客户代码过多地依赖于对象容器复杂的内部实现结构,对象容器内部实现结构(而非抽象接口)的变化将因其客户代码的频繁变化,带来了代码的维护性、扩展性等弊端。
如何将“客户代码与复杂的对象容器结构”解耦?让对象容器自己来实现自身的复杂结构,从而使得客户代码就像处理简单对象一样来处理复杂的对象容器?
(三)模式定义
将对象组合成树形结构以表示“部分-整体”的层级结构。Compisite使得用户对单个对象和组合对象的使用具有一致性 (稳定)。
——《设计模式》GoF
(四)代码讲解
1.抽象接口
class Component
{
public:
virtual void process() = ;
virtual ~Component(){}
};
2.两种类型之一:树形结构
//树节点
class Composite : public Component{ string name;
list<Component*> elements; //表达了一个树形结构
public:
Composite(const string & s) : name(s) {} void add(Component* element) {
elements.push_back(element);
}
void remove(Component* element){
elements.remove(element);
} void process(){
//1. process current node //2. process leaf nodes
for (auto &e : elements) //会出现多态递归调用,可能是树节点也可能是叶子节点
e->process(); //多态调用
}
};
2.两种类型之一:叶子节点
//叶子节点
class Leaf : public Component{
string name;
public:
Leaf(string s) : name(s) {} void process(){
//process current node
}
};
3.客户程序
void Invoke(Component & c){ //可以是树节点或者叶子节点
//...
c.process(); //多态调用
//...
}
4.实现构建树
int main()
{ Composite root("root");
Composite treeNode1("treeNode1");
Composite treeNode2("treeNode2");
Composite treeNode3("treeNode3");
Composite treeNode4("treeNode4");
Leaf leat1("left1");
Leaf leat2("left2"); root.add(&treeNode1);
treeNode1.add(&treeNode2);
treeNode2.add(&leaf1); root.add(&treeNode3);
treeNode3.add(&treeNode4);
treeNode4.add(&leaf2); Invoke(root);
Invoke(leaf2);
Invoke(treeNode3); }
问题:若是不用composite模式,如何实现?
//树节点
class Composite : public Component{ string name;
list<Component*> elements;
public:
Composite(const string & s) : name(s) {} void add(Component* element) {
elements.push_back(element);
}
void remove(Component* element){
elements.remove(element);
} void process(){ //1. process current node
}
}; //叶子节点
class Leaf : public Component{
string name;
public:
Leaf(string s) : name(s) {} void process(){
//process current node
}
};
会导致:
void Invoke(Component & c){
//...
c.process(); //这个地方的处理要做分别处理,进行判断类别,然后进行递归,依赖于对象容器内部的复杂结构
//...
}
(五)类图(结构)

类比文件系统:

(六)要点总结
(一)Composite模式采用树形结构来实现普遍存在的对象容器,从而将“一对多”的关系转化为“一对一”的关系,使得客户代码可以一致地(复用)处理对象和对象容器,无需关心处理的是单个对象还是组合的对象容器。
若是不用composite模式,我们在Invoke中需要进行多种判断类型,是一对多,但是我们使用了composite模式,我们只需要使用一个process即可,无需更新内部是什么,统一处理
(二)将“客户代码与复杂的对象容器结构”解耦是Composite的核心思想,解耦之后,客户代码将与纯粹的抽象接口——而非对象容器的内部实现结构——发生依赖,从而更能“应对变化”。
(三)Composite模式在具体实现中,可以让父对象中的子对象反向追溯;如果父对象有频繁的遍历需求,可使用缓存技巧来改善效率
(七)案例实现(文件列表)
1.接口实现
//抽象接口
class Component
{
public:
virtual void display() = ;
virtual ~Component(){}
};
2.树形结构:文件夹
//树形结构,文件夹
class Folder :public Component
{
private:
string f_name;
list<Component*> f_list;
public:
Folder(string name)
{
f_name = name;
} virtual void display()
{
cout << "d\t" << f_name << endl;
for (auto &f : f_list)
f->display();
} void Add(Component* comp)
{
f_list.push_back(comp);
} void Remove(Component* comp)
{
f_list.remove(comp);
} list<Component*> GetChild()
{
return f_list;
}
};
3.叶子节点:文件夹
//叶子节点,文件
class File :public Component
{
private:
string f_name;
public:
File(string name)
{
f_name = name;
} virtual void display()
{
cout << "f\t" << f_name << endl;
}
};
4.创建演示
void main()
{
Folder* root = new Folder("C:"); Folder* dir1 = new Folder("System32");
Folder* dir2 = new Folder("drivers");
Folder* dir3 = new Folder("etc"); File* file1 = new File("SAII_LOG.TXT");
File* file2 = new File("hosts"); root->Add(dir1);
dir1->Add(dir2);
dir1->Add(file1);
dir2->Add(dir3);
dir3->Add(file2); root->display();
cout << "==========================" << endl;
dir3->Remove(file2);
File* file3 = new File("config.ini");
dir3->Add(file3);
root->display(); delete dir1;
delete dir2;
delete dir3;
delete file1;
delete file2;
delete file3; system("pause");
return;
}

设计模式---数据结构模式之组合模式(Composite)的更多相关文章
- 设计模式(七)组合模式Composite(结构型)
设计模式(七)组合模式Composite(结构型) 1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件和文件夹目录 2.问题 ...
- 设计模式的征途—9.组合(Composite)模式
树形结构在软件中随处可见,比如操作系统中的目录结构,公司组织结构等等,如何运用面向对象的方式来处理这种树形结构是组合模式需要解决的问题.组合模式通过一种巧妙的设计方案来使得用户可以一致性地处理整个树形 ...
- Java设计模式(8)组合模式(Composite模式)
Composite定义:将对象以树形结构组织起来,以达成“部分-整体” 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性. Composite比较容易理解,想到Composite就应该想到树 ...
- 迭代器模式和组合模式(head first设计模式——8)
把迭代器模式和组合模式放在同一篇的原因是其联系比较紧密. 一.迭代器模式 1.1迭代器模式定义 迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而不是暴露其内部的表示. 这个模式提供了一种方法 ...
- 设计模式GOF23(结构型模式:代理模式,适配模式,桥接模式,组合模式,装饰模式,外观模式,享元模式)
结构型模式: – 分类: • 适配器模式.代理模式.桥接模式.装饰模式.组合模式.外观模式.享元模式 – 核心作用:是从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题. 结构 ...
- 设计模式(十)——组合模式(HashMap源码解析)
1 看一个学校院系展示需求 编写程序展示一个学校院系结构:需求是这样,要在一个页面中展示出学校的院系组成,一个学校有多个学院, 一个学院有多个系.如图: 2 传统方案解决学校院系展示 3 传统方案解决 ...
- js设计模式(六)---组合模式
组合模式将对象组合成树形结构,以表示“部分-整体”的层次结构.除了用来表示树形结构之外,组合模式的另一个好处是通过对象的多态性表现,使得用户对单个对象和组合对象的使用具有一致性.基本图例 1.组合模式 ...
- JS设计模式(7)组合模式
什么是组合模式? 定义:1.将对象组合成树形结构以表示"部分-整体"的层次结构.2.组合模式使得用户对单个对象和组合对象的使用具有一致性.3.无须关心对象有多少层,调用时只需在根部 ...
- Java计模模式之六 ----- 组合模式和过滤器模式
前言 在上一篇中我们学习了结构型模式的外观模式和装饰器模式.本篇则来学习下组合模式和过滤器模式. 组合模式 简介 组合模式是用于把一组相似的对象当作一个单一的对象.组合模式依据树形结构来组合对象,用来 ...
随机推荐
- python之旅七【第七篇】面向对象之类成员
面向对象的类成员 相关知识点 一 字段 字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同, 普通字段属于对象 静态字段属于类 class Provinc ...
- BZOJ1014[JSOI2008]火星人——非旋转treap+二分答案+hash
题目描述 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 ...
- Codeforces Round #449 Div. 1
B:注意到nc/2<=m,于是以c/2为界决定数放在左边还是右边,保证序列满足性质的前提下替换掉一个数使得其更靠近边界即可. #include<iostream> #include& ...
- POJ 1966 Cable TV Network (算竞进阶习题)
拆点+网络流 拆点建图应该是很常见的套路了..一张无向图不联通,那么肯定有两个点不联通,但是我们不知道这两个点是什么. 所以我们枚举所有点,并把每个点拆成入点和出点,每次把枚举的两个点的入点作为s和t ...
- Python里format()方法基本使用
'''第一种:自然连接''' #format 连接字符串 str = '{}使用的python是{}版本'.format('我','3.6.5') print(str) #打印结果:我使用的pytho ...
- Ionic生命周期与注意点
需要注意的地方是:在走页面的生命周期以前,会先走构造方法 构造方法只走一次,除非再次创建这个页面.所以如果先push了一个新页面,然后再调用pop()返回到之前的页面,那么是不会走构造方法里面的方法的 ...
- C/C++ 程序库
C/C++ 程序库 // --------------------------------------------- 来几个不常见但是很变态的库吧: bundle: 把几乎所有常见的压缩库封装成了一个 ...
- Fiddler中显示IP方法
如何在fiddler查看到请求的IP地址?就像下面这样 打开fiddler, 快捷键Ctrl+R 或者 菜单->Rules->Customize Rules…,然后在CustomRul ...
- Codeforces访问提速攻略(小技巧)
update 这篇文章已废,因为有了 http://m1.codeforces.com codeforces是不是很慢呢?反正蒟蒻打比赛的时候经常几分钟打不开题面然后就被吊打了... 于是几番周折整理 ...
- Hdoj 1789 Doing Homework again 题解
Problem Description Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of h ...