15.1 场 景 问 题

15.1.1 商品类别树

考虑这样一个实际的应用:管理商品类别树。

在实现跟商品有关的应用系统的时候,一个很常见的功能就是商品类别树的管理,比如有以下的商品类别树:

图片

仔细观察上面的商品类别树,有以下几个明显的特点。

■ 有一个根节点,比如服装,它没有父节点,它可以包含其他的节点。

■ 树枝节点,有一类节点可以包含其他的节点,称之为树枝节点,比如男装、女装。

■ 叶子节点,有一类节点没有子节点,称之为叶子节点,比如衬衣、夹克、裙子、套装。

现在需要管理商品类别树,假如要求能实现输出如上商品类别树的结构功能,应该如何实现呢?

15.1.2 不用模式的解决方案

要管理商品类别树,就是要管理树的各个节点。现在树上的节点有三类,根节点、树枝节点和叶子节点,再进一步分析发现,根节点和树枝节点是类似的,都是可以包含其他节点的节点,把它们称为容器节点。

这样一来,商品类别树的节点就被分成了两种,一种是容器节点,另一种是叶子节点。容器节点可以包含其他的容器节点或者叶子节点。把它们分别实现成为对象,也就是容器对象和叶子对象,容器对象可以包含其他的容器对象或者叶子对象。换句话说,容器对象是一种组合对象。

然后在组合对象和叶子对象里面去实现要求的功能就可以了,看看下面的代码实现。

(1)先来看看叶子对象的代码实现。示例代码如下:

d6bf45a9a09b4e16af7fa73ec76a40ef

0c9523c79a9641bd9eeccd15d6eadef9

(2)再来看看组合对象的代码实现。组合对象里面可以包含其他的组合对象或者是叶子对象,由于类型不一样,需要分开记录。示例代码如下:

5e40e87f48c840058f46c4e01ce6559a

57c1148269ba40cd9a0b339e8df0e1bd

3018d690defd43ac91f3b15cf7e34ab0

0b2d71a826404475b39ba7bf067eebba

(3)写个客户端来测试一下,看看是否能实现要求的功能。示例代码如下:

954ac21a8460432bb4aa02f29e842045

运行一下,测试看看,是否能完成要求的功能。

15.1.3 有何问题

上面的实现,虽然能实现要求的功能,但是有一个很明显的问题:那就是必须区分组合对象和叶子对象,并进行有区别的对待,比如在Composite和Client里面,都需要去区别对待这两种对象。

区别对待组合对象和叶子对象,不仅让程序变得复杂,还对功能的扩展也带来不便。实际上,大多数情况下用户并不想要去区别它们,而是认为它们是一样的,这样他们操作起来最简单。

对于这种具有整体与部分关系,并能组合成树型结构的对象结构,如何才能够以一个统一的方式来进行操作呢?