欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

组合模式(Composite Pattern)

程序员文章站 2022-07-02 16:29:27
组合模式概述 定义:组合多个对象形成树形结构以表示具有部分-整体关系的层次结构。组合模式让客户端可以统一对待单个对象和组合对象。又被成为“部分-整体”(Part-Whole)模式,属于对象结构性模式 定义什么的,最枯燥了。简单的来说,就如我们鼠标右击新建文件夹一样,在一个磁盘里,我们可以新建一个文件 ......
  • 组合模式概述

定义:组合多个对象形成树形结构以表示具有部分-整体关系的层次结构。组合模式让客户端可以统一对待单个对象和组合对象。又被成为“部分-整体”(part-whole)模式,属于对象结构性模式

定义什么的,最枯燥了。简单的来说,就如我们鼠标右击新建文件夹一样,在一个磁盘里,我们可以新建一个文件夹a,也可以新建某个类型的文件a,a和a都在同一目录下,当然,我们也可以点击进入文件夹a,在a中新建新的文件夹b,也可以在a中新建文件b。只要是文件夹,就可以在里面继续新建文件夹和文件,而文件则只能用来放数据,不能在新建了。

组合模式(Composite Pattern)

当然,也可以通过win+r调出运行,输入cmd(commmand),进入你想查看文件的磁盘,输入tree命令,就可以结构性的查看所有文件。在上述图中可以看出文件结构就如同一棵树,有文件夹,有文件,我们把文件成为叶子(laef),因为文件不能再展开了,就如树形结构中叶子是最底层了;把文件夹称为容器(container),因为文件夹里既可以文件夹,又可以放文件。当想要查看一个磁盘的所有文件时,可以使用dfs(深度优先搜索)即递归的对每个文件夹进行同样的搜索,一条路走到底,当访问到叶子结点时,再退回去访问别的结点。

  • 组合模式结构和实现

组合模式(Composite Pattern)

  1. component(抽象构件):它可以是接口或抽象类,为叶子构件和容器构件对象声明接口。定义了访问管理它的子构件的方法,就是对一个子构件该有的操作都应该在这声明,如创建子构件,删除子构件,打开子构件,重命名子构件,复制子构件.......
  2. leaf(叶子构件):代表一个文件,实现在component中的行为,即对文件的操作,可以是读文件,写文件,删除文件,复制文件......
  3. composite(容器构件):代表一个文件夹,它提供一个集合放子节点,可以是文件夹,也可以是文件,所以它有一个聚合箭头指向component,代表可以递归的创建构件
 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 }
 8 class leaf : component
 9 {
10     public override void add(component c)
11     {
12         //throw new notimplementedexception();//这里是报错,叶子文件没有此方法的
13     }
14     
15     public override void remove(component c)
16     {
17         //throw new notimplementedexception();//同上
18     }
19     
20     public override component getchild(int i )
21     {
22         //throw new notimplementedexception();//同上
23         return null;
24     }
25     
26     public override void operation()
27     {
28         //对文件的可执行方法
29     }    
30 }
31 class composite : component
32 {
33     private ilist<component> list = new list<component>();//这里通链表容器存放文件夹
34     public override void add(component c)
35     {
36         list.add(c);
37     }
38     
39     public override void remoce(component c)
40     {
41         list.remove(c);
42     }
43     
44     public override component getchild(int i )
45     {
46         return (component)list(c);
47     }
48     
49     public override void operation()
50     {
51         //递归实现容器中的对文件的方法
52         foreach(component child in list)
53         {
54             (component)child.operation();
55         }
56     }    
57 }
  • 组合模式的应用

 教育机构的oa系统要给各办公室下发公文(issuedbytheofficedoucument),采用组合模式模拟实现

组合模式(Composite Pattern)

分析:从图中可以看出,北京总部,湖南分校,长沙叫教学点,湘潭教学点这几个有子构件,所以它们为文件容器,而教务办公室,行政办公室即为叶子,当然,每个叶子是不同的,要区别开。因此我们定义一个抽象机构类(abstractinstitutions),其中声明add,remove,getchild和issuedbytheofficedoucument方法

1  abstract class abstractinstitutions//component
2     {
3         public abstract void add(abstractinstitutions institutions);
4         public abstract void remove(abstractinstitutions institutions);
5         public abstract abstractinstitutions getchild(int i);
6         public abstract void issuedbytheofficedoucument();
7     }

教务办公室,有自己的名字,即哪一个教务办公室,它只能收到下发的公文

 1  class academicaffairsoffice : abstractinstitutions//leaf 教务办公室
 2     {
 3         private string name;
 4         public academicaffairsoffice(string name)
 5         {
 6             this.name = name;
 7         }
 8         public override void add(abstractinstitutions institutions)
 9         {
10             console.writeline("can't realize this method!!!");
11         }
12 
13         public override void remove(abstractinstitutions institutions)
14         {
15             console.writeline("can't realize this method!!!");
16         }
17 
18         public override abstractinstitutions getchild(int i)
19         {
20             console.writeline("can't realize this method!!!");
21             return null;
22         }
23 
24         public override void issuedbytheofficedoucument()
25         {
26             console.writeline("issued by the office doucument to the {0}",name);
27         }
28     }

行政办公室和教务办公室类似的实现

 1 class administrationoffice : abstractinstitutions//leaf  行政办公室
 2     {
 3          private string name;
 4         public administrationoffice(string name)
 5         {
 6             this.name = name;
 7         }
 8 
 9         public override void add(abstractinstitutions institutions)
10         {
11             console.writeline("can't realize this method!!!");
12         }
13 
14         public override void remove(abstractinstitutions institutions)
15         {
16             console.writeline("can't realize this method!!!");
17         }
18 
19         public override abstractinstitutions getchild(int i)
20         {
21             console.writeline("can't realize this method!!!");
22             return null;
23         }
24 
25         public override void issuedbytheofficedoucument()
26         {
27             console.writeline("issued by the office doucument to the {0}", name);
28         }
29     }

容器类中实现抽象构件中的方法,并且要向下属机构下发公文

 1 class teacharea : abstractinstitutions//composite //教学点
 2     {
 3         private string name;
 4         private ilist<abstractinstitutions> arealist = new list<abstractinstitutions>();
 5        
 6         public teacharea(string name)
 7         {
 8             this.name = name;
 9         }
10 
11         public override void add(abstractinstitutions institutions)
12         {
13             arealist.add(institutions);
14         }
15 
16         public override void remove(abstractinstitutions institutions)
17         {
18             arealist.remove(institutions);
19         }
20 
21         public override abstractinstitutions getchild(int i)
22         {
23             return (abstractinstitutions)arealist[i];
24         }
25 
26         public override void issuedbytheofficedoucument()
27         {
28             console.writeline("issue official documents to the {0}", name);
29             foreach (object obj in arealist)
30             {
31                 ((abstractinstitutions)obj).issuedbytheofficedoucument();
32             }
33         }
34     }

program中,要将所有的机构创建出来,并一一add到对应的容器中,最后有由北京总部向下发送公文

 1 class program
 2     {
 3         static void main(string[] args)
 4         {
 5             abstractinstitutions beijingheadquarters;
 6             beijingheadquarters = new teacharea("beijingheadquarters");
 7 
 8             abstractinstitutions beijingacademicaffairsoffice;
 9             beijingacademicaffairsoffice = new academicaffairsoffice("beijingacademicaffairsoffice");
10             administrationoffice beijingadministrationoffice;
11             beijingadministrationoffice = new administrationoffice("beijingadministrationoffice");
12 
13             abstractinstitutions hunanpartition;
14             hunanpartition = new teacharea("hunanpartition");
15 
16             abstractinstitutions hunanchangshaarea;
17             hunanchangshaarea = new teacharea("hunanchangshaarea");
18 
19             abstractinstitutions hunanxiangtanarea;
20             hunanxiangtanarea = new teacharea("hunanxiangtanarea");
21 
22             abstractinstitutions hunanacademicaffairoffice;
23             hunanacademicaffairoffice = new academicaffairsoffice("hunanacademicaffairoffice");
24             abstractinstitutions hunanadministrationoffice;
25             hunanadministrationoffice = new administrationoffice("hunanadministrationoffice");
26 
27             console.writeline();
28             abstractinstitutions changshaacademicaffairoffice;
29             changshaacademicaffairoffice = new academicaffairsoffice("changshaacademicaffairoffice");
30 
31             abstractinstitutions changshaadministrationoffice;
32             changshaadministrationoffice = new administrationoffice("changshaadministrationoffice");
33             abstractinstitutions xiangtanacademicaffairoffice;
34             xiangtanacademicaffairoffice = new academicaffairsoffice("xiangtanacademicaffairoffice");
35 
36             abstractinstitutions xiangtanadministrationoffice;
37             xiangtanadministrationoffice = new administrationoffice("xiangtanadministrationoffice");
38 
39             hunanchangshaarea.add(changshaacademicaffairoffice);
40             hunanchangshaarea.add(changshaadministrationoffice);
41 
42             hunanxiangtanarea.add(xiangtanacademicaffairoffice);
43             hunanxiangtanarea.add(xiangtanadministrationoffice);
44 
45             hunanpartition.add(hunanchangshaarea);
46             hunanpartition.add(hunanxiangtanarea);
47             hunanpartition.add(hunanacademicaffairoffice);
48             hunanpartition.add(hunanadministrationoffice);
49 
50             beijingheadquarters.add(beijingacademicaffairsoffice);
51             beijingheadquarters.add(beijingadministrationoffice);
52             beijingheadquarters.add(hunanpartition);
53             beijingheadquarters.issuedbytheofficedoucument();
54         }
55     }

运行结果:

组合模式(Composite Pattern)

  • 透明组合模式和安全组合模式

  • 透明组合模式

component中声明所有的方法,这样满足了一致性的原则,即对叶子和容器对象都是一样的处理,不需用再去判断,这个对象是叶子还是容器啊,如果是容器,可以实现哪些方法,如果是叶子,又只能实现哪些方法。这些判断都不需要。但是,由于叶子也继承了component的方法,因此不安全,叶子对象不能调用add,remove,getchild的方法,如果运行时调用,会出错,因此要提供错误处理代码(如上述例子中的( console.writeline("can't realize this method!!!");

组合模式(Composite Pattern)

  • 安全组合模式

component中没有声明任何方法,而是在composite中声明并实现,这样做不会因为leaf调用错误的方法而报错,但缺点是不够透明,即要区别的对待叶子构件和容器构件,但是日常使用是很多的,毕竟安全的往往好很多

组合模式(Composite Pattern)

上面的例子使用了透明组合模式

  • 组合模式的优缺点和适用环境

  • 组合模式的优点:
  1. 可以清楚的定义分层次的复杂对象,表示对象的全部会部分层次,让客户忽略层次的差异,方便控制
  2. 客户端可以一致性的使用一个组合结构或其中单个对象,不必关心处理的是单个对象(叶子文件)还是组合结构(文件夹容器),简化了客户端代码
  3. 增加新的容器构件和叶子构件很方便
  4. 为树型结构的面向对象实现了一种灵活的解决方案
  • 组合模式的缺点:
  1. 在增加新的构件时很难对容器中的构件类型进行控制。如果我希望文件夹里只能放文件时,则需要复杂的实现过程来实现
  • 组合模式的适用环境
  1. 在具有整体和部分层次的结构中,希望通过一种方式忽略整体与部分的差异,一致的对待它们
  2. 在一个使用面向对象语言开发的系统中要处理一个树形结构时
  3. 在一个系统总能够分离出叶子和容器对象,而且它们的类型不固定,需要增加一些新的类型