我相信大家小时候都玩过积木,回忆一下,我们玩过的积木大致分两种:一种是各种形状的木块,我们只要根据自己的想象往上搭就可以搭建出各式各样的小房子、小汽车;而另一种是后来才出现的塑料积木,它的形状较前者少,主要特点是一块就是一个颜色(前者往往只有一面有颜色,不过常常是图案而不仅仅是单色块),较薄,一面是凸点,一面是凹槽,所以可以在不断地叠加过程中组成新的更大的模块。我们在此就以第二种积木作为组合模式的比喻素材。
我们首先来分析一下这种积木,它的形状比较单一,通常是一块扁平的立方体,一面是规则排列的凸起的圆柱体,一面则是规则排列的凹进的圆柱槽,圆柱体的体积正好等于圆柱槽的容积,因此我们正好可以以此来固定住任意两块相邻的积木,在不考虑积木数量限制的情况下,我们可以无限叠加这些积木。我们再来看看玩积木的场景,其实小孩子是不会把一块积木和一堆积木分开来看的,他们不会认为一块积木和一堆积木是两种不同的事物,或许是他们思维太简单,也或许是我们思想太复杂,总之,一块积木是积木,一堆积木它还是积木。把一块积木树立起来,我们可以说它是一扇门(的确很像我国古代那种带门钉的木门),要是觉得不过瘾,我们也可以用一堆积木块来搭建出一个更大的更逼真的大门。
组合模式就适用于这样的场景:用一致的方式来对待和处理单一对象以及由这种单一对象组成的组合体。
1: using System;
2: using System.Collections;
3:
4: namespace Autumoon.DesignPatterns.Composite
5: {
6: public abstract class Brick
7: {
8: protected string Name { get; private set; }
9:
10: public Brick(string name)
11: {
12: this.Name = name;
13: }
14:
15: abstract public void Add(Brick brick);
16:
17: abstract public void Output();
18: }
19:
20: public class ToyBlocks : Brick
21: {
22: private ArrayList ComponentList = new ArrayList();
23:
24: public ToyBlocks(string name) : base(name) { }
25:
26: override public void Add(Brick brick)
27: {
28: ComponentList.Add(brick);
29: }
30:
31: override public void Output()
32: {
33: Console.WriteLine("Brick: " + Name);
34:
35: foreach (Brick component in ComponentList)
36: {
37: component.Output();
38: }
39: }
40: }
41:
42: public class Leaf : Brick
43: {
44: public Leaf(string name) : base(name) { }
45:
46: override public void Add(Brick brick)
47: {
48: Console.WriteLine("Cannot add to a leaf");
49: }
50:
51: override public void Output()
52: {
53: Console.WriteLine("Brick: " + Name);
54: }
55: }
56:
57: public class CompositeClient
58: {
59: /// <summary>
60: /// To create the toy bricks structure.
61: /// </summary>
62: /// <returns></returns>
63: public Brick PlayToyBricks()
64: {
65: // Now we'll create the toy bricks structure, it's made by composites and leafs.
66: ToyBlocks root = new ToyBlocks("Root-Composite");
67: ToyBlocks parentcomposite = root;
68: ToyBlocks composite = new ToyBlocks("First Level - First Sibling - Composite");
69: Leaf leaf = new Leaf("First Level - Second Sibling - Leaf");
70:
71: parentcomposite.Add(composite);
72: parentcomposite.Add(leaf);
73: parentcomposite = composite;
74: composite = new ToyBlocks("Second Level - First Sibling - Composite");
75: parentcomposite.Add(composite);
76: composite = new ToyBlocks("Second Level - Second Sibling - Composite");
77: parentcomposite.Add(composite);
78:
79: parentcomposite = composite;
80: leaf = new Leaf("Third Level - First Sibling - Leaf");
81: parentcomposite.Add(leaf);
82:
83: leaf = new Leaf("Third Level - Second Sibling - Leaf");
84: parentcomposite.Add(leaf);
85: composite = new ToyBlocks("Third Level - Third Sibling - Composite");
86: parentcomposite.Add(composite);
87:
88: return root;
89: }
90: }
91: }
通过代码我们可以看到,无论是组合体“ToyBricks”还是单一个体“Leaf”,都继承自抽象类“Brick”,因此我们就可以用一致的方式来操作这两种子类了。接下来,我们就来玩一把积木,重温一下儿时的乐趣吧。
1: static void Main(string[] args)
2: {
3: #region Composite
4: new CompositeClient().PlayToyBricks().Output();
5: #endregion
6:
7: Console.ReadLine();
8: }