zoukankan      html  css  js  c++  java
  • 设计模式:组合模式(Composite Pattern) 明

    作者:TerryLee  创建于:2006-03-11 出处:http://terrylee.cnblogs.com/archive/2006/03/11/347919.html  收录于:2013-02-28

    结构图


     

    意图


    将对象组合成树形结构以表示“部分-整体”的层次结构。Composite模式使得用户对单个对象和组合对象的使用具有一致性。

    适用性


    • 你想表示对象的部分-整体层次结构。
    • 你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。 

    实现代码


     这里我们用绘图这个例子来说明Composite模式,通过一些基本图像元素(直线、圆等)以及一些复合图像元素(由基本图像元素组合而成)构建复杂的图形树。在设计中我们对每一个对象都配备一个Draw()方法,在调用时,会显示相关的图形。可以看到,这里复合图像元素它在充当对象的同时,又是那些基本图像元素的一个容器。先看一下基本的类结构图:

     1 using System;
     2 using System.Collections;
     3 public abstract class Graphics
     4 {
     5     protected string _name;
     6     public Graphics(string name)
     7     {
     8         this._name = name;
     9     }
    10     public abstract void Draw();
    11     public abstract void Add();
    12     public abstract void Remove();
    13 }
    14 public class Picture : Graphics
    15 {
    16     protected ArrayList picList = new ArrayList();
    17     public Picture(string name) : base(name)
    18     { }
    19     public override void Draw()
    20     {
    21         Console.WriteLine("Draw a" + _name.ToString());
    22         foreach (Graphics g in picList)
    23         {
    24             g.Draw();
    25         }
    26     }
    27     public override void Add(Graphics g)
    28     {
    29         picList.Add(g);
    30     }
    31     public override void Remove(Graphics g)
    32     {
    33         picList.Remove(g);
    34     }
    35 }
    36 public class Line : Graphics
    37 {
    38     public Line(string name) : base(name)
    39     { }
    40     public override void Draw()
    41     {
    42         Console.WriteLine("Draw a" + _name.ToString());
    43     }
    44     public override void Add(Graphics g)
    45     {
    46         //抛出一个我们自定义的异常
    47     }
    48     public override void Remove(Graphics g)
    49     {
    50         //抛出一个我们自定义的异常
    51     }
    52 }
    53 public class Circle : Graphics
    54 {
    55     public Circle(string name): base(name)
    56     { }
    57     public override void Draw()
    58     {
    59         Console.WriteLine("Draw a" + _name.ToString());
    60     }
    61     public override void Add(Graphics g)
    62     {
    63         //抛出一个我们自定义的异常
    64     }
    65     public override void Remove(Graphics g)
    66     {
    67         //抛出一个我们自定义的异常
    68     }
    69 }
    70 public class Rectangle : Graphics
    71 {
    72     public Rectangle(string name): base(name)
    73     { }
    74     public override void Draw()
    75     {
    76         Console.WriteLine("Draw a" + _name.ToString());
    77     }
    78     public override void Add(Graphics g)
    79     {
    80         //抛出一个我们自定义的异常
    81     }
    82     public override void Remove(Graphics g)
    83     {
    84         //抛出一个我们自定义的异常
    85     }
    86 }

    因为Line,Rectangle,Circle已经没有了子对象,它是一个基本图像元素,因此Add(),Remove()的方法对于它来说没有任何意义,而且把这种错误不会在编译的时候报错,所以需要抛出异常。

    这样改进以后,我们可以捕获可能出现的错误,做进一步的处理。上面的这种实现方法属于透明式的Composite模式,如果我们想要更安全的一种做法,就需要把管理子对象的方法声明在树枝构件Picture类里面,这样如果叶子节点Line,Rectangle,Circle使用这些方法时,在编译期就会出错,看一下类结构图:

     1 using System;
     2 using System.Collections;
     3 public abstract class Graphics
     4 {
     5     protected string _name;
     6     public Graphics(string name)
     7     {
     8         this._name = name;
     9     }
    10     public abstract void Draw();
    11 }
    12 public class Picture : Graphics
    13 {
    14     protected ArrayList picList = new ArrayList();
    15     public Picture(string name): base(name)
    16     { }
    17     public override void Draw()
    18     {
    19         Console.WriteLine("Draw a" + _name.ToString());
    20         foreach (Graphics g in picList)
    21         {
    22             g.Draw();
    23         }
    24     }
    25     public void Add(Graphics g)
    26     {
    27         picList.Add(g);
    28     }
    29     public void Remove(Graphics g)
    30     {
    31         picList.Remove(g);
    32     }
    33 }
    34 public class Line : Graphics
    35 {
    36     public Line(string name): base(name)
    37     { }
    38     public override void Draw()
    39     {
    40         Console.WriteLine("Draw a" + _name.ToString());
    41     }
    42 }
    43 public class Circle : Graphics
    44 {
    45     public Circle(string name) : base(name)
    46     { }
    47     public override void Draw()
    48     {
    49         Console.WriteLine("Draw a" + _name.ToString());
    50     }
    51 }
    52 public class Rectangle : Graphics
    53 {
    54     public Rectangle(string name) : base(name)
    55     { }
    56     public override void Draw()
    57     {
    58         Console.WriteLine("Draw a" + _name.ToString());
    59     }
    60 }

    这种方式属于安全式的Composite模式,在这种方式下,虽然避免了前面所讨论的错误,但是它也使得叶子节点和树枝构件具有不一样的接口。这种方式和透明式的Composite各有优劣,具体使用哪一个,需要根据问题的实际情况而定。

    以下是客户端代码

     1 public class App
     2 {
     3     public static void Main()
     4     {
     5         Picture root = new Picture("Root");
     6         root.Add(new Line("Line"));
     7         root.Add(new Circle("Circle"));
     8         Rectangle r = new Rectangle("Rectangle");
     9         root.Add(r);
    10         root.Draw();
    11     }
    12 }

    效果及实现要点


    1.Composite模式采用树形结构来实现普遍存在的对象容器,从而将“一对多”的关系转化“一对一”的关系,使得客户代码可以一致地处理对象和对象容器,无需关心处理的是单个的对象,还是组合的对象容器。

    2.将“客户代码与复杂的对象容器结构”解耦是Composite模式的核心思想,解耦之后,客户代码将与纯粹的抽象接口——而非对象容器的复内部实现结构——发生依赖关系,从而更能“应对变化”。

    3.Composite模式中,是将“Add和Remove等和对象容器相关的方法”定义在“表示抽象对象的Component类”中,还是将其定义在“表示对象容器的Composite类”中,是一个关乎“透明性”和“安全性”的两难问题,需要仔细权衡。这里有可能违背面向对象的“单一职责原则”,但是对于这种特殊结构,这又是必须付出的代价。ASP.NET控件的实现在这方面为我们提供了一个很好的示范。

    4.Composite模式在具体实现中,可以让父对象中的子对象反向追溯;如果父对象有频繁的遍历需求,可使用缓存技巧来改善效率。

  • 相关阅读:
    20145319 《信息安全系统设计基础》第0周学习总结
    20145319 《java程序设计》课程总结
    20145319 第十周学习总结
    20145319 实验五
    20145319 实验四
    20145319 第九周学习总结
    20145319 第八周学习总结
    20145319 实验三
    20145319 第七周学习总结
    20145312 《Java程序设计》第六周学习总结
  • 原文地址:https://www.cnblogs.com/Ming8006/p/2937344.html
Copyright © 2011-2022 走看看