组合模式的定义与特点

组合(Composite Pattern)模式的定义:有时又叫作整体-部分(Part-Whole)模式,它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的访问性,属于结构型设计模式。
组合模式一般用来描述整体与部分的关系,它将对象组织到树形结构中,顶层的节点被称为根节点,根节点下面可以包含树枝节点和叶子节点,树枝节点下面又可以包含树枝节点和叶子节点,树形结构图如下。
设计模式-组合模式(Composite) - 图1
根节点和树枝节点本质上属于同一种数据类型,可以作为容器使用;而叶子节点与树枝节点在语义上不属于用一种类型。但是在组合模式中,会把树枝节点和叶子节点看作属于同一种数据类型(用统一接口定义),让它们具备一致行为。

组合模式的主要优点

  1. 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码;
  2. 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”

    其主要缺点

  3. 设计较复杂,客户端需要花更多时间理清类之间的层次关系;

  4. 不容易限制容器中的构件;
  5. 不容易用继承的方法来增加构件的新功能;

    组合模式的结构与实现

    组合模式分为透明式的组合模式和安全式的组合模式。

    透明方式

    在该方式中,由于抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。但其缺点是:树叶构件本来没有 Add()、Remove() 及 GetChild() 方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。
    实现例图

    1. //抽象构件
    2. public interface abstractConposite
    3. {
    4. public void add(abstractConposite c);
    5. public void remove(abstractConposite c);
    6. public abstractConposite getChild(int i);
    7. public void operation();
    8. }
    9. //树枝构件
    10. public class Root : abstractConposite
    11. {
    12. private List<abstractConposite> children = new List<abstractConposite>();
    13. public void add(abstractConposite c)
    14. {
    15. children.Add(c);
    16. }
    17. public abstractConposite getChild(int i)
    18. {
    19. return children[i];
    20. }
    21. public void operation()
    22. {
    23. foreach (var child in children)
    24. {
    25. child.operation();
    26. }
    27. }
    28. public void remove(abstractConposite c)
    29. {
    30. children.Remove(c);
    31. }
    32. }
    33. //树叶构件
    34. public class Leaf : abstractConposite
    35. {
    36. private string name;
    37. public Leaf(string name)
    38. {
    39. this.name = name;
    40. }
    41. public void add(abstractConposite c)
    42. {
    43. //树叶是没有分支的,此处空实现
    44. }
    45. public abstractConposite getChild(int i)
    46. {
    47. return null;
    48. }
    49. public void operation()
    50. {
    51. Debug.Log("树叶 "+name+" 被访问");
    52. }
    53. public void remove(abstractConposite c)
    54. {
    55. }
    56. }
    1. void Start()
    2. {
    3. abstractConposite root0 = new Root();
    4. abstractConposite root1 = new Root();
    5. abstractConposite leaf1 = new Leaf("left1");
    6. abstractConposite leaf2 = new Leaf("left2");
    7. abstractConposite leaf3 = new Leaf("left3");
    8. root0.add(leaf1);
    9. root0.add(root1);
    10. root1.add(leaf2);
    11. root1.add(leaf3);
    12. root0.operation();
    13. }
    14. //测试结果
    15. //树叶 left1 被访问
    16. //树叶 left2 被访问
    17. //树叶 left3 被访问

    安全方式

    在该方式中,将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了上一种方式的安全性问题,但由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,所以失去了透明性。

    1. //抽象层只保留层次的公共行为
    2. interface abstractConposite {
    3. public void operation();
    4. }
    1. //由于把管理方法交给根构件中了,因此不能像之前用 抽象=new root 来做
    2. void Start()
    3. {
    4. Root root0 = new Root();
    5. Root root1 = new Root();
    6. abstractConposite leaf1 = new Leaf("left1");
    7. abstractConposite leaf2 = new Leaf("left2");
    8. abstractConposite leaf3 = new Leaf("left3");
    9. root0.add(leaf1);
    10. root0.add(root1);
    11. root1.add(leaf2);
    12. root1.add(leaf3);
    13. root0.operation();
    14. }

    组合模式的应用场景

    前面分析了组合模式的结构与特点,下面分析它适用的以下应用场景。

  6. 在需要表示一个对象整体与部分的层次结构的场合。

  7. 要求对用户隐藏组合对象与单个对象的不同,用户可以用统一的接口使用组合结构中的所有对象的场合。

    组合模式的扩展

    对组合模式中的树叶节点和树枝节点进行抽象,也就是说树叶节点和树枝节点还有子节点,这时组合模式就扩展成复杂的组合模式了
    设计模式-组合模式(Composite) - 图3