从零开始学习Java设计模式 | 结构型模式篇:组合模式

Posted 李阿昀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从零开始学习Java设计模式 | 结构型模式篇:组合模式相关的知识,希望对你有一定的参考价值。

在本讲,我们来学习一下结构型模式里面的第六个设计模式,即组合模式。

概述

在学习组合模式之前,我们先来看下面这张图。

对于以上这张图大家应该很熟悉,我们可以将其看作是一个文件系统,其实说到底它就是Windows系统里面的一个目录结构,只不过对于Windows中的文件系统而言,它里面包含有C盘、D盘、E盘等等盘符,而这里我们只是以它里面的某一个盘符里面的目录结构为例来进行了一个描述。

对于这样的结构我们称之为树形结构。为啥叫树形结构呢?你看一下上图中的左边部分,最上面是不是有一个WINDOWS目录啊,而该WINDOWS目录下面又有很多的子目录或者子文件,这样,我们就能将其描述成上图右边部分的树形结构了,它是不是很像一棵倒着的树啊!既然是一棵树,那么它就只有一个树根了,很明显,这个树根就是最顶层的WINDOWS目录,在该目录下,自然就会生成许多的子文件或者子文件夹了,而如果要是子文件夹的话,那么它下面又可以有许多的子文件或者子文件夹了,以此类推,一棵参天大树就长成了。

对于这样一个文件系统而言,有几个概念大家需要知道一下,文件夹或者文件我们都可称之为节点,但是一般来说,我们称文件为叶子节点,称文件夹为树枝节点,这是因为树枝还可以再去生成子树枝或者子叶子。

在这样一个树形结构中,我们可以通过调用某个方法来遍历整棵树,当我们找到某个叶子节点后,就可以对叶子节点进行相关的操作了。因此,我们不妨将这颗树理解成一个大的容器,容器里面包含有很多的成员对象(其实就是节点对象),这些成员对象既可以是容器对象(即文件夹,当然你也可以把它称作是树枝对象)也可以是叶子对象(即文件)。但是由于容器对象和叶子对象在功能上面有所区别(区别是很明显的,叶子对象,即文件,可以读写数据,但是它下面不可能再有子文件或者子文件夹了;而容器对象,即文件夹,它下面是可以再有子文件或者子文件的,但是它不能进行数据的一个读写操作),使得我们在使用的过程中必须要区分容器对象和叶子对象,但是这样一来就会给客户带来不必要的麻烦,对于客户来说的话,他始终是希望能够一致的对待容器对象和叶子对象。也就是说,对于客户而言,不管是文件夹还是文件,他都希望一致的去对待它们,即把它们都当作同样的一个对象来进行处理。

至此,我们就认识了一下以上树形结构,并且咱们还知道了该树形结构所存在的一个问题。那如何解决该问题呢?很明显,就要用到组合模式了,因为本文讲的就是组合模式嘛!

那什么是组合模式呢?下面我们来看看它的概念。

组合模式又名部分整体模式(啥又叫部分整体模式呢?上面不是说过嘛,我们可以将一棵树理解成一个大的容器,对于该容器而言,它就是整体;然后它下面不是又有子文件或者子文件夹嘛,这些子文件或者子文件夹我们就称之为部分,当然,部分下面是不是还可以再分出部分来啊!),是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次,这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。

看完以上组合模式的概念之后,相信大家就能知道应该要使用组合模式来解决以上树形结构所存在的问题了,因为对于客户而言,他就能一致的去对待容器对象和叶子对象了,这样,他使用起来也会变得更加简单。

结构

组合模式主要包含有三种角色:

  • 抽象根节点(Component):定义系统各层次对象具有的共有方法和属性,可以预先定义一些默认行为和属性。

    怎么来理解抽象根节点呢?还是通过上图来理解,不管是文件夹还是文件,我们都可以向上抽取,抽取出一个抽象类,而在这个抽象类里面,我们就可以去定义文件和文件夹中的共有行为和属性了。也就是说,正是因为客户他想要一致的去对待容器对象和叶子对象,所以他就可以定义出这么一个公共的抽象类了

  • 树枝节点(Composite):定义树枝节点的行为,即存储子节点,组合树枝节点和叶子节点形成一个树形结构。

  • 叶子节点(Leaf):叶子节点对象,其下再无分支,是系统层次遍历的最小单位。

组合模式案例

接下来,我们就通过一个案例再来理解一下组合模式,这个案例就是软件菜单。

分析

先来看一下下面这张图。

相信大家还是比较熟悉以上这张图的,因为我们在访问别的一些管理系统时,经常可以看到类似的菜单。一个菜单可以包含菜单项(菜单项是指不再包含其他内容的菜单条目),也可以包含带有其他菜单项的菜单,就拿以上系统管理菜单来说,它下面有三个子菜单,分别是菜单管理、权限配置、角色管理,它们都是属于菜单,因为它们下面还可以有子菜单或者子菜单项。对于菜单管理来说,它下面有五个子菜单项,分别是页面访问、展开菜单、编辑菜单、删除菜单、新增菜单,注意了,它们都是菜单项,下面不可能再有子菜单或者子菜单项了,故它们都是属于叶子节点;而系统管理、菜单管理、权限配置、角色管理,它们均属于树枝节点,并且系统管理从根本上来说,它是属于根节点。因此,使用组合模式来描述以上菜单就很恰当了。

这样,我们的需求就是针对一个菜单,例如系统管理,打印出其包含的所有菜单以及菜单项的名称。

需求明确之后,接下来我们就要编写代码解决该需求了。首先,对于该需求,我们先设计出一个如下的类图。
。。。

实现

。。。

以上是关于从零开始学习Java设计模式 | 结构型模式篇:组合模式的主要内容,如果未能解决你的问题,请参考以下文章

从零开始学习Java设计模式 | 结构型模式篇:组合模式

从零开始学习Java设计模式 | 结构型模式篇:组合模式

从零开始学习Java设计模式 | 结构型模式篇:装饰者模式

从零开始学习Java设计模式 | 结构型模式篇:装饰者模式

从零开始学习Java设计模式 | 结构型模式篇:外观模式

从零开始学习Java设计模式 | 结构型模式篇:外观模式