设计模式---数据结构模式之组合模式(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计模模式之六 ----- 组合模式和过滤器模式
前言 在上一篇中我们学习了结构型模式的外观模式和装饰器模式.本篇则来学习下组合模式和过滤器模式. 组合模式 简介 组合模式是用于把一组相似的对象当作一个单一的对象.组合模式依据树形结构来组合对象,用来 ...
随机推荐
- Codeforces Round #472 Div. 1
A:某个格子被染黑说明该行和该列同时被选中,使用并查集合并,最后看每个集合中是否有未被染黑的格子即可. #include<iostream> #include<cstdio> ...
- Python入门-编写抓取网站图片的爬虫-正则表达式
//生命太短 我用Python! //Python真是让一直用c++的村里孩子长知识了! 这个仅仅是一个测试,成功抓取了某网站1000多张图片. 下一步要做一个大新闻 大工程 #config = ut ...
- 洛谷3703 [SDOI2017] 树点染色 【LCT】【线段树】
题目分析: 操作一很明显等价于LCT上的access操作,操作二是常识,操作三转化到dfs序上求最大值也是常识.access的时候顺便在线段树中把对应部分-1,把右子树的子树+1即可. 代码: #in ...
- ALGO-19 审美课
算法训练 审美课 时间限制:1.0s 内存限制:256.0MB 问题描述 <审美的历程>课上有n位学生,帅老师展示了m幅画,其中有些是梵高的作品,另外的都出自五岁小朋 ...
- 【BZOJ4126】【BZOJ3516】【BZOJ3157】国王奇遇记 线性插值
题目描述 三倍经验题. 给你\(n,m\),求 \[ \sum_{i=1}^ni^mm^i \] \(n\leq {10}^9,1\leq m\leq 500000\) 题解 当\(m=1\)时\(a ...
- Markdown文本的学习
大标题 小标题 小小标题 小小小标题 萌啊萌啊萌 斜体 萌啊萌啊萌 粗体 萌啊萌啊萌 又粗又斜 萌啊萌啊萌 我是分割线 p.s. 标准Markdown换行要打两个空格 短代码 #include < ...
- nagios 监控内存使用情况
监控本机内存cd /usr/lib64/nagios/pluginstouch check_mem.sh #!/bin/bash " ]; then memTotal_b=`free -b ...
- Android LinearLayout 渐变背景
更多 参考 Drawable Resources | Android Developers main_header.xml: <?xml version="1.0" enc ...
- Arukas.io云主机安装CentOS
创建应用 1 jdeathe/centos-ssh:centos-6 启动应用 电机启动应用,应用会自动部署,等显示Running 就说明成功了.估计需要几分钟. 查看用户以及密码 自己保存下用户 ...
- Jupyter ~ 像写文章般的 Coding (附:同一个ipynb文件,执行多语言代码)
前面用了好久Notebook来交互式编程了,这次说说几个其他的选项: Notebook Markdown 这次选Markdown模式(关于Markdown基础可以看之前写的Markdown Base) ...