设计模式——组合模式

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

组合模式的使用类似于树的结构。在树结构中主要有两类对象,一个是子节点,一个是父节点。

父节点中可以包含子节点,而子节点之下则不能拥有父节点。(比较适用在递归结构中)

以文件的资料夹为例:

按照正常理解,单个文件如图片格式,文本格式,文件夹我们应该每个都独立的抽象出一个类,在他们的具体类中进行相应的操作,

但是如此一来功能类就会有些冗余。借鉴代码如下:

图片类

 1    class ImageFile
 2     {
 3         private String name;
 4 
 5         public ImageFile(String name)
 6         {
 7             this.name = name;
 8         }
 9 
10         public void killVirus() {  
11         //简化代码,模拟杀毒  
12        Console.WriteLine("----对图像文件'" + name + "'进行杀毒");  
13     }  
14     }

文本类

 1  class TextFile
 2     {
 3         private String name;
 4 
 5         public TextFile(String name)
 6         {
 7             this.name = name;
 8         }
 9 
10         public void killVirus() {  
11         //简化代码,模拟杀毒  
12         Console.WriteLine("----对文本文件'" + name + "'进行杀毒");
13     }  
14     }

文件夹类

 1  class Folder
 2     {
 3         private String name;
 4         //定义集合folderList,用于存储Folder类型的成员  
 5         private List<Folder> folderList = new List<Folder>();
 6         //定义集合imageList,用于存储ImageFile类型的成员  
 7         private List<ImageFile> imageList = new List<ImageFile>();
 8         //定义集合textList,用于存储TextFile类型的成员  
 9         private List<TextFile> textList = new List<TextFile>();
10 
11         public Folder(String name)
12         {
13             this.name = name;
14         }
15 
16         //增加新的Folder类型的成员  
17         public void addFolder(Folder f)
18         {
19             folderList.Add(f);
20         }
21 
22         //增加新的ImageFile类型的成员  
23         public void addImageFile(ImageFile image)
24         {
25             imageList.Add(image);
26         }
27 
28         //增加新的TextFile类型的成员  
29         public void addTextFile(TextFile text)
30         {
31             textList.Add(text);
32         }
33 
34         //需提供三个不同的方法removeFolder()、removeImageFile()和removeTextFile()来删除成员,代码省略  
35 
36         //需提供三个不同的方法getChildFolder(int i)、getChildImageFile(int i)和getChildTextFile(int i)来获取成员,代码省略  
37 
38         public void killVirus() {  
39         Console.WriteLine("****对文件夹'" + name + "'进行杀毒");  //模拟杀毒  
40           
41         //如果是Folder类型的成员,递归调用Folder的killVirus()方法  
42         foreach(Object obj in folderList) {  
43             ((Folder)obj).killVirus();  
44         }  
45           
46         //如果是ImageFile类型的成员,调用ImageFile的killVirus()方法  
47         foreach(Object obj in imageList) {  
48             ((ImageFile)obj).killVirus();  
49         }  
50           
51         //如果是TextFile类型的成员,调用TextFile的killVirus()方法  
52         foreach(Object obj in textList) {  
53             ((TextFile)obj).killVirus();  
54         }  
55     }   
56     }

调用方法

            Folder folder1, folder2, folder3;
            folder1 = new Folder("Sunny的资料");
            folder2 = new Folder("图像文件");
            folder3 = new Folder("文本文件");

            ImageFile image1, image2;
            image1 = new ImageFile("小龙女.jpg");
            image2 = new ImageFile("张无忌.gif");

            TextFile text1, text2;
            text1 = new TextFile("九阴真经.txt");
            text2 = new TextFile("葵花宝典.doc");

            folder2.addImageFile(image1);
            folder2.addImageFile(image2);
            folder3.addTextFile(text1);
            folder3.addTextFile(text2);
            folder1.addFolder(folder2);
            folder1.addFolder(folder3);

            folder1.killVirus();
            Console.Read();

对文件夹的病毒查杀也就这样完成了,但是现在看起来,文件夹类中的东西太多,对每一个类型的文件都有增,删,查,代码太过冗余。

系统没有提供抽象层,文件类和文件夹类需要当做两个对象对待。

灵活性太差,当需要增加或者改变文件类时需要大动干戈。

这时便能用上组合模式了!

组合模式的主要作用是将父节点和叶子节点当做同一种类型对待,将两者抽象出一种类,这样使用两者就有了一致性。

      在组合模式结构图中包含如下几个角色:

      ● Component(抽象构件):它可以是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法,如增加子构件、删除子构件、获取子构件等。

      ● Leaf(叶子构件):它在组合结构中表示叶子节点对象,叶子节点没有子节点,它实现了在抽象构件中定义的行为。对于那些访问及管理子构件的方法,可以通过异常等方式进行处理。

      ● Composite(容器构件):它在组合结构中表示容器节点对象,容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点,它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。

      组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器,而客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。同时容器对象与抽象构件类之间还建立一个聚合关联关系,在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成一个树形结构。

抽象出的类:

1  abstract class Component
2     {
3         public abstract void add(Component c); //增加成员  
4         public abstract void remove(Component c); //删除成员  
5         public abstract Component getChild(int i); //获取成员  
6         public abstract void operation();  //业务方法 
7     }

文本类

 1 class TextFile:Component
 2     {
 3         private String name;
 4 
 5         public TextFile(String name)
 6         {  
 7           this.name = name;  
 8         }
 9         public override void add(Component c)
10         {
11             Console.WriteLine("对不起,不支持该方法!"); 
12         }
13         public override void remove(Component c)
14         {
15             Console.WriteLine("对不起,不支持该方法!"); 
16         }
17         public override Component getChild(int i)
18         {
19             return null;
20         }
21         public override void operation()
22         {
23             Console.WriteLine("----对文本文件'" + name + "'进行杀毒"); 
24         }
25     }

图片类

 1  private String name;
 2         public ImageFile(String name)
 3         {  
 4           this.name = name;  
 5         }
 6         public override void add(Component c)
 7         { 
 8         Console.WriteLine("对不起,不支持该方法!");  
 9         }
10         public override void remove(Component c)
11         {
12             Console.WriteLine("对不起,不支持该方法!"); 
13         }
14         public override Component getChild(int i)
15         {
16             return null;
17         }
18         public override void operation()
19         { 
20          Console.WriteLine("----对图片文件'" + name + "'进行杀毒");  
21         }

文件夹类

 1 class Folder:Component
 2     {
 3         private List<Component> list = new List<Component>();
 4 
 5         private String name;
 6 
 7         public Folder(String name)
 8         {
 9             this.name = name;
10         }  
11         public override  void add(Component c)
12         {
13             list.Add(c);
14         }
15         public override void remove(Component c)
16         {
17             list.Remove(c);
18         }
19         public override Component getChild(int i)
20         {
21             return (Component)list[i];  
22         }
23         public override void operation()
24         {
25          Console.WriteLine("****对文件夹'" + name + "'进行杀毒");  //模拟杀毒  
26           
27         //递归调用成员构件的killVirus()方法  
28          foreach (Object obj in list)
29          {
30              ((Component)obj).operation();  
31          }  
32         }
33     }

测试

 1    //针对抽象构件编程  
 2             Component file1, file2, file3, file4, file5, folder1, folder2, folder3, folder4;
 3 
 4             folder1 = new Folder("Sunny的资料");
 5             folder2 = new Folder("图像文件");
 6             folder3 = new Folder("文本文件"); 8 
 9             file1 = new ImageFile("小龙女.jpg");
10             file2 = new ImageFile("张无忌.gif");
11             file3 = new TextFile("九阴真经.txt");
12             file4 = new TextFile("葵花宝典.doc");
13 
14             folder2.add(file1);
15             folder2.add(file2);
16             folder3.add(file3);
17             folder3.add(file4);
18             folder1.add(folder2);
19             folder1.add(folder3);
20             folder1.add(folder4);
21 
22             //从“Sunny的资料”节点开始进行杀毒操作  
23             folder1.operation();
24             Console.ReadLine();

组合模式又分为透明组合模式与安全组合模式。

上述的组合模式为透明组合。将子节点与父节点的功能全部放入一个抽象类中,如果有一方(子节点或父节点)没有此功能,则使用错误处理代码。

安全组合模式则是将父节点与子节点的相同类抽象出来,而每个对象的特殊类在各自现实类中完成。

安全组合模式:

将相同功能抽象出来

1 abstract class AbstractFile {  
2     public abstract void operation();
3 }

具体实现片段

1     AbstractFile file1,file2,file3,file4,file5;  
2     Folder folder1,folder2,folder3,folder4; //不能透明处理容器构件  
3         //其他代码省略  

还是比较考虑优先使用透明组合安全模式。应为这样抽象的程度加大,便于后期维护。

学习于   https://www.cnblogs.com/lfxiao/p/6816026.html

猜你喜欢

转载自www.cnblogs.com/cwmizlp/p/9052477.html