上一篇博客中我们从从电影院中认识了"迭代器模式"(Iterator Pattern),今天我们就从文件系统中来认识一下“组合模式”(Composite Pattern)。说到组合模式,在此我想聊一下在类图中有组合与聚合的关系,这两者都是整体和部分的关系,只是整体与部分的依赖度不同。在聚合关系中,整体强烈依赖于部分,而部分脱离于整体将没有存在的意义,比如你身上的器官与你的关系就是聚合关系。而对于组合关系来说整体与部分的依赖就相对于小一些,离开彼此也是可以独立生存的,比如员工与公司的关系,就是组合关系。

言归正传,今天我们来介绍一下“组合模式”。下方就是组合模式的定义:

组合模式:允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象已经对象组合

组合模式也就是将多个独立的个体组合到一块,不过组合时是有层级关系的,而这些层级关系是“树”形的关系。典型的树状层级关系就是我们的文件系统,下方截图就是我们资源管理器的一个文件层级的截图。可以明确的看出下方是树状的层级关系。今天我们的任务就是使用“组合模式”模拟下方的文件结构。从下方的截图中我们可以分析出文件总体上可以分为两种类型,一个是文件夹,在一个就是真正有内容的文件。文件夹是一种容器,它不仅可以存储文件还可以存储文件夹。文件夹可以存储文件以及其他文件夹,这一特性就决定文件系统是一个树形结构。

一、模拟“文件系统”实现的类图设计

依旧是老套路,我们要使用代码结合“组合模式”来模仿上面截图中的文件结构,首先我们先来设计类图,然后在根据我们设计的类图来给出代码实现。上面我们已经提到过文件夹就是可以存储其他文件夹和文件的容器,所以在我们设计实现是打算使用Dictionary(字典)来实现这一容器的特性,至于如何去实现下方会给出具体的实现方式。下方的类图就是我们要实现的“文件系统”的类图,当然我们是模拟的,尽量的简化了一些操作。下方也使用了组合模式,Folder类就是组合文件夹与文件的地方,稍后会给出具体的说明。

首先我们来介绍下方黄色框中的文件类型协议与该协议的延展。FileType是我们所有文件的协议,无论是文件夹还是具体文件都遵循该协议,该协议中给出了文件以及文件夹的必要操作。在该协议的默认延展中给出了协议中那些只需要文件夹实现而具体文件不需要实现的方法,如addFile()、deleteFile()方法,只有文件夹容器才会有这些方法。该协议的具体呢绒如下类图中黄框中的内容所示。

然后是红框中的部分,红框中是我们文件夹的实现,也是我们组合模式的核心模块。经过观察Folder(文件夹)类,我们不难发现Folder不仅仅遵循了FileType接口,还依赖于FileType接口。因为Folder是文件的一种类型,所以要遵循FileType接口。同时Folder是文件的容器,可以存放所有的文件和文件夹(也就是遵循FileType接口的所有类),所以Folder依赖于FileType接口。这个特性决定了组合模式有着树形结构。

最后是绿框中的部分,该部分的代码比较单纯。绿框中是具体文件的类。该模块有一个基类,也就是BaseFile。所有的具体文件都继承自BaseFile,因为BaseFile也是文件的一种所以也需要遵循FileType协议。因为具体文件不是容器,不需要实现addFile()等容器使用到的方法。因为具体文件遵循了FileType协议,而Folder依赖于FileType协议,所以Folder可以存储具体文件。整体的类图如下所示:

二、“文件系统”的代码实现

有了上面的类图,再给出相应的代码实现就容易的多了。接下来我们就根据上面的类图,给出相应的Swift代码实现。首先我们会给出FileType协议以及其延展的实现,具体代码片段如下所示。getFileName()方法用户获取文件名,addFile(file)用于文件夹添加文件,deleteFile(file)用于文件夹删除文件,display()用于打印文件名。FileType延展中给出了具体文件不需要实现的方法,所以在延展中给出了一个默认的实现,类似于抽象类中的方法实现。因为在协议延展中给出了方法的默认实现,所以在文件类中的可以不给出协议延展中的方法。FileType与其延展的代码段如下所示。

实现完相关的接口和扩展后就开始实现我们的具体类了,接下来我们将要给出组合模式的核心类Folder(容器类)。下方的Folder就是我们用代码实现的文件夹,Folder遵循了FileType接口,并给出了相应方法的具体实现。在Folder中我们要注意一下files属性,该属性就是组合的聚集地。我们可以看出files的类型是一个字典,字典的key是String类型,而字典的Value是FileType类型。也就是说files中可以存储遵循FileType协议的所有类,也就是files中可以存储文件和文件夹。“组合模式”在此处的提现就是文件以及文件夹在一块进行组合会生成一个新的文件夹。

下方还需要注意的就是Folder中的display()方法。该方法是遍历files数组,然后取出其中的文件或者文件夹对象,然后调用这些对象的display()方法。这样就会输出当前文件夹下所有的文件的名称。Folder文件夹类的具体实现方式如下所示:

上面给出了文件夹的实现,接着我们要实现另一种文件类型,就是具体的文件了。在实现具体文件时,我们定义了一个具体文件的基类,就是BaseFile。当然BaseFile也遵循与FileType协议,这就是我们面向接口编程。在BaseFile基类中我们给出了所有文件所共有的方法,比如getFileName()和display()方法。接着我们又实现了两个特定的文件类型,一个Swift源文件SwiftFile,另一个就是Objective-C源文件ObjCFile。这两个具体的文件都继承自BaseFile类。具体代码实现如下所示:

三、测试用例

接下来就到了测试用例的部分了,也就是上面类图中的Client的部分。Client就是该文件系统的使用者,从类图中我们可以看出来,Client依赖于FileType接口而不依赖于具体实现。因为我们是在Xcode中的Playground中做的测试,所以我们就没有给出具体的Client类。但是下方代码就等同于Client类中的代码。下方就是我们的测试用例我们构建了本文开头的文件目录结构,并输出了文件夹下所有文件的名称。测试用例与输出结果如下所示:

至此我们的“组合模式”的一个完整示例就执行完了。

同样今天的Demo也会在github上进行分享,分享地址为:https://github.com/lizelu/DesignPatterns-Swift

设计模式(十一):从文Finder中认识"组合模式"(Composite Pattern)的更多相关文章

  1. 设计模式系列之组合模式(Composite Pattern)——树形结构的处理

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  2. 浅谈设计模式--组合模式(Composite Pattern)

    组合模式(Composite Pattern) 组合模式,有时候又叫部分-整体结构(part-whole hierarchy),使得用户对单个对象和对一组对象的使用具有一致性.简单来说,就是可以像使用 ...

  3. 乐在其中设计模式(C#) - 组合模式(Composite Pattern)

    原文:乐在其中设计模式(C#) - 组合模式(Composite Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 组合模式(Composite Pattern) 作者:weba ...

  4. 【设计模式】组合模式 Composite Pattern

    树形结构是软件行业很常见的一种结构,几乎随处可见,  比如: HTML 页面中的DOM,产品的分类,通常一些应用或网站的菜单,Windows Form 中的控件继承关系,Android中的View继承 ...

  5. 二十四种设计模式:组合模式(Composite Pattern)

    组合模式(Composite Pattern) 介绍将对象组合成树形结构以表示"部分-整体"的层次结构.它使得客户对单个对象和复合对象的使用具有一致性.示例有一个Message实体 ...

  6. 设计模式 - 组合模式(composite pattern) 迭代器(iterator) 具体解释

    组合模式(composite pattern) 迭代器(iterator) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考组合模式(composit ...

  7. python 设计模式之组合模式Composite Pattern

    #引入一 文件夹对我们来说很熟悉,文件夹里面可以包含文件夹,也可以包含文件. 那么文件夹是个容器,文件夹里面的文件夹也是个容器,文件夹里面的文件是对象. 这是一个树形结构 咱们生活工作中常用的一种结构 ...

  8. C#设计模式——组合模式(Composite Pattern)

    一.概述 在软件开发中,我们往往会遇上类似树形结构的对象体系.即某一对象既可能在树形结构中作为叶节点存在,也可能作为分支节点存在.比如在文件系统中,文件是作为叶节点存在,而文件夹就是分支节点.在设计这 ...

  9. 设计模式 -- 组合模式 (Composite Pattern)

    定义: 对象组合成部分整体结构,单个对象和组合对象具有一致性. 看了下大概结构就是集团总公司和子公司那种层级结构. 角色介绍: Component :抽象根节点:其实相当去总公司,抽象子类共有的方法: ...

随机推荐

  1. Hadoop 中利用 mapreduce 读写 mysql 数据

    Hadoop 中利用 mapreduce 读写 mysql 数据   有时候我们在项目中会遇到输入结果集很大,但是输出结果很小,比如一些 pv.uv 数据,然后为了实时查询的需求,或者一些 OLAP ...

  2. Angular2学习笔记(1)

    Angular2学习笔记(1) 1. 写在前面 之前基于Electron写过一个Markdown编辑器.就其功能而言,主要功能已经实现,一些小的不影响使用的功能由于时间关系还没有完成:但就代码而言,之 ...

  3. Sublime Text 3中文乱码解决方法以及安装包管理器方法

    一般出现乱码是因为文本采用了GBK编码格式,Sublime Text默认不支持GBK编码. 安装包管理器 简单安装 使用Ctrl+`快捷键或者通过View->Show Console菜单打开命令 ...

  4. 10个最好用的HTML/CSS 工具、插件和资料库

    大家在使用HTML/CSS开发项目的过程中,有使用过哪些工具,插件和库?下面介绍的10种HTML/CSS工具,插件和资料库,是国外程序员经常用到的. Firebug Lite FirebugLite ...

  5. requests的content与text导致lxml的解析问题

    title: requests的content与text导致lxml的解析问题 date: 2015-04-29 22:49:31 categories: 经验 tags: [Python,lxml, ...

  6. C# 正则表达式大全

    文章导读 正则表达式的本质是使用一系列特殊字符模式,来表示某一类字符串.正则表达式无疑是处理文本最有力的工具,而.NET提供的Regex类实现了验证正则表达式的方法.Regex 类表示不可变(只读)的 ...

  7. CentOS7 重置root密码

    1- 在启动grub菜单,选择编辑选项启动 2 - 按键盘e键,来进入编辑界面 3 - 找到Linux 16的那一行,将ro改为rw init=/sysroot/bin/sh 4 - 现在按下 Con ...

  8. MVC常遇见的几个场景代码分享

    本次主要分享几个场景的处理代码,有更好处理方式多多交流,相互促进进步:代码由来主要是这几天使用前端Ace框架做后台管理系统,这Ace是H5框架里面的控件效果挺多的,做兼容也很好,有点遗憾是控件效果基本 ...

  9. html5 canvas常用api总结(二)--绘图API

    canvas可以绘制出很多奇妙的样式和美丽的效果,通过几个简单的api就可以在画布上呈现出千变万化的效果,还可以制作网页游戏,接下来就总结一下和绘图有关的API. 绘画的时候canvas相当于画布,而 ...

  10. SharpMap简析

    1.背景 因为项目需求,需要基于开源项目来对SHP进行相关操作.涉及到的主要功能就是加载SHP读取其中的属性信息和几何信息.于是选择了Sharpmap来进行,在使用中对其相关功能做了初步了解,做个总结 ...