15.1 场 景 问 题
15.1.1 商品类别树
考虑这样一个实际的应用:管理商品类别树。
在实现跟商品有关的应用系统的时候,一个很常见的功能就是商品类别树的管理,比如有以下的商品类别树:
仔细观察上面的商品类别树,有以下几个明显的特点。
■ 有一个根节点,比如服装,它没有父节点,它可以包含其他的节点。
■ 树枝节点,有一类节点可以包含其他的节点,称之为树枝节点,比如男装、女装。
■ 叶子节点,有一类节点没有子节点,称之为叶子节点,比如衬衣、夹克、裙子、套装。
现在需要管理商品类别树,假如要求能实现输出如上商品类别树的结构功能,应该如何实现呢?
15.1.2 不用模式的解决方案
要管理商品类别树,就是要管理树的各个节点。现在树上的节点有三类,根节点、树枝节点和叶子节点,再进一步分析发现,根节点和树枝节点是类似的,都是可以包含其他节点的节点,把它们称为容器节点。
这样一来,商品类别树的节点就被分成了两种,一种是容器节点,另一种是叶子节点。容器节点可以包含其他的容器节点或者叶子节点。把它们分别实现成为对象,也就是容器对象和叶子对象,容器对象可以包含其他的容器对象或者叶子对象。换句话说,容器对象是一种组合对象。
然后在组合对象和叶子对象里面去实现要求的功能就可以了,看看下面的代码实现。
(1)先来看看叶子对象的代码实现。示例代码如下:
(2)再来看看组合对象的代码实现。组合对象里面可以包含其他的组合对象或者是叶子对象,由于类型不一样,需要分开记录。示例代码如下:
(3)写个客户端来测试一下,看看是否能实现要求的功能。示例代码如下:
15.1.3 有何问题
上面的实现,虽然能实现要求的功能,但是有一个很明显的问题:那就是必须区分组合对象和叶子对象,并进行有区别的对待,比如在Composite和Client里面,都需要去区别对待这两种对象。
区别对待组合对象和叶子对象,不仅让程序变得复杂,还对功能的扩展也带来不便。实际上,大多数情况下用户并不想要去区别它们,而是认为它们是一样的,这样他们操作起来最简单。