前提:数据结构模式

常常有一些组建在内部具有特定的数据结构,如果让客户程序依赖这些特定的数据结构,将极大的破坏组件的复用。这时候,将这些数据结构封装在内部,在外部提供统一的接口,来实现与特定数据结构无关的访问,是一种行之有效的解决方案。

典型模式

组合模式: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)的更多相关文章

  1. 设计模式(七)组合模式Composite(结构型)

    设计模式(七)组合模式Composite(结构型) 1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件和文件夹目录 2.问题 ...

  2. 设计模式的征途—9.组合(Composite)模式

    树形结构在软件中随处可见,比如操作系统中的目录结构,公司组织结构等等,如何运用面向对象的方式来处理这种树形结构是组合模式需要解决的问题.组合模式通过一种巧妙的设计方案来使得用户可以一致性地处理整个树形 ...

  3. Java设计模式(8)组合模式(Composite模式)

    Composite定义:将对象以树形结构组织起来,以达成“部分-整体” 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性. Composite比较容易理解,想到Composite就应该想到树 ...

  4. 迭代器模式和组合模式(head first设计模式——8)

    把迭代器模式和组合模式放在同一篇的原因是其联系比较紧密. 一.迭代器模式 1.1迭代器模式定义 迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而不是暴露其内部的表示. 这个模式提供了一种方法 ...

  5. 设计模式GOF23(结构型模式:代理模式,适配模式,桥接模式,组合模式,装饰模式,外观模式,享元模式)

    结构型模式: – 分类: • 适配器模式.代理模式.桥接模式.装饰模式.组合模式.外观模式.享元模式 – 核心作用:是从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题.   结构 ...

  6. 设计模式(十)——组合模式(HashMap源码解析)

    1 看一个学校院系展示需求 编写程序展示一个学校院系结构:需求是这样,要在一个页面中展示出学校的院系组成,一个学校有多个学院, 一个学院有多个系.如图: 2 传统方案解决学校院系展示 3 传统方案解决 ...

  7. js设计模式(六)---组合模式

    组合模式将对象组合成树形结构,以表示“部分-整体”的层次结构.除了用来表示树形结构之外,组合模式的另一个好处是通过对象的多态性表现,使得用户对单个对象和组合对象的使用具有一致性.基本图例 1.组合模式 ...

  8. JS设计模式(7)组合模式

    什么是组合模式? 定义:1.将对象组合成树形结构以表示"部分-整体"的层次结构.2.组合模式使得用户对单个对象和组合对象的使用具有一致性.3.无须关心对象有多少层,调用时只需在根部 ...

  9. Java计模模式之六 ----- 组合模式和过滤器模式

    前言 在上一篇中我们学习了结构型模式的外观模式和装饰器模式.本篇则来学习下组合模式和过滤器模式. 组合模式 简介 组合模式是用于把一组相似的对象当作一个单一的对象.组合模式依据树形结构来组合对象,用来 ...

随机推荐

  1. Flask 构建微电影视频网站(一)

    Flask构建电影视频网站 Python MTV模型 Flask微内核 Flask扩展插件配置及使用方法 根据业务开发网站前后台功能 Flask结合MySQL数据库 你将可以独立开发网站 独立部署运维 ...

  2. Django+Xadmin打造在线教育系统(四)

    完成授课机构的功能 模板继承 在templates目录下,新建base.html,剪切org-list.html内容到里面 编写org-list.html内容 继承base.html,将里面的面包屑和 ...

  3. 概念数据模型CDM基础

    概念数据模型CDM 概念数据模型是设计数据库不可或缺的一步,是整个数据库设计的关键,CDM的主要作用如下: 1)能够真实地模拟真实世界,是需求分析人员和数据库设计人员沟通的桥梁.2)将系统需求分析得到 ...

  4. HGOI 20190310 题解

    /* 又是又双叒叕WA的一天... 我太弱鸡了... 今天上午打了4道CF */ Problem 1 meaning 给出q组询问,求下列函数的值$ f(a) = \max\limits_{0 < ...

  5. Think Python 2E中译本 _site

    http://codingpy.com/books/thinkpython2/index.html

  6. Navicat Premium 12 破解(MySQL、MariaDB、MongoDB、SQL Server、SQLite)

    打开注入到安装目录中的exe中 破解提示(还没好,继续看下去) 如果你安装的是中文版,选一下中文版(英文默认即可),获取一下key(名字和组织可以自定义) 打开Navicat,选择注册(第一次打开选注 ...

  7. bzoj2252 矩阵距离

    很好奇这种 普及- 的题为什么会是权限题...... 我一开始想用枚举 + 搜索,看书后发现自己脑抽了.直接BFS即可. #include <cstdio> #include <qu ...

  8. iconv: iconv_open(pToCharset, pFromCharset); 的附加参数//IGNORE

    今天在转换一个文件时iconv() 老是返回 -1, 提示编码转换失败. 一共 30 多个文件, 原编码都是一样的,为什么有的转换会失败,返回 -1呢? 网上搜索了一下, 找到一个随加参数: //IG ...

  9. CF1129D Isolation(分块+DP)

    一个很显然的DP方程式:f[i]=Σf[j],其中j<i且在[j+1,i]中出现1次的数不超过k个 乍一看挺神仙的,只会O(n^2),就是对于每个位置从后向前扫一遍,边扫边统计出现1次的数的个数 ...

  10. php+mysql简单的添加和删除小案例

    1.分析 index.php是呈现列表,通过点击列表页上的添加和删除按钮,对列表页上面的进行操作 index.php TODO:要将数据库里面的内容呈现到页面中 (1)连接数据库 (2)查询数据 (3 ...