好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

深入理解Java设计模式之组合模式

一、什么是组合模式

定义 :将对象以树形结构组织起来,以达成[部分-整体]的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。

动机(motivation)

客户代码过多地依赖于对象容器复杂的内部实现结构,对象容器内部实现结构(而非抽象接口)的变化将引起客户代码的频繁变化,带来了代码的维护性、扩展性等弊端。

如何将[客户代码与复杂的对象容器结构]解耦?让对象容器自己来实现自身的复杂结构,从而使得客户代码就像处理简单对象一样来处理复杂的对象容器?

意图(intent)

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

组合模式,现在学习就是虚类继承虚类,然后增加虚方法。最终实类继承第二个虚类,重写所有虚方法。

二、组合模式的结构

结构图说明:

(1) component :组合中的对象声明接口,在适当情况下实现所有类共有的默认行为,声明一个接口用于访问和管理component的子组件。在递归结构中定义一个接口,用于访问一个父部件,并在合适的情况下实现它。(可选)

(2) leaf :在组合中表示叶节点,叶节点没有子节点,定义对象的基本行为。

(3) composite :定义有子部件的那些部件的行为,存储子部件并在component接口实现与子部件有关的操作。

(4) client :通过component接口操作组合部件的对象。

三、组合模式的使用场景

1.需求重要体现部分与整体的层次结构时

2.你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

四、组合模式的优缺点

优点

1.使客户端调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不必关系自己处理的是单个对象还是整个组合结构,这就简化了客户端代码。

2.更容易在组合体内加入对象部件. 客户端不必因为加入了新的对象部件而更改代码。

缺点

组合模式不容易限制组合中的构件。

五、组合模式的实现

组合模式有两种实现方式,一种是:透明式的组合模式,另外一种是:安全式的组合模式。在这里我就详细说一下何为[透明式],何为[安全式]。所谓透明式是指[抽象构件角色]定义的接口行为集合包含两个部分,一部分是叶子对象本身所包含的行为(比如operation),另外一部分是容器对象本身所包含的管理子对象的行为(add,remove)。这个抽象构件必须同时包含这两类对象所有的行为,客户端代码才会透明的使用,无论调用容器对象还是叶子对象,接口方法都是一样的,这就是透明,针对客户端代码的透明,但是也有他自己的问题,叶子对象不会包含自己的子对象,为什么要有add,remove等类似方法呢,调用叶子对象这样的方法可能(注意:我这里说的是可能,因为有些人会把这些方法实现为空,不做任何动作,当然也不会有异常抛出了,不要抬杠)会抛出异常,这样就不安全了,然后人们就提出了[安全式的组合模式]。所谓安全式是指[抽象构件角色]只定义叶子对象的方法,确切的说这个抽象构件只定义两类对象共有的行为,然后容器对象的方法定义在[树枝构件角色]上,这样叶子对象有叶子对象的方法,容器对象有容器对象的方法,这样责任很明确,当然调用肯定不会抛出异常了。大家可以根据自己的情况自行选择是实现为[透视式]还是[安全式]的,以下我们会针对这两种情况都有实现,具体实现如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

namespace 透明式的组合模式的实现

{

     /// <summary>

     /// 该抽象类就是文件夹抽象接口的定义,该类型就相当于是抽象构件component类型

     /// </summary>

     public abstract class folder

     {

         //增加文件夹或文件

         public abstract void add(folder folder);

         //删除文件夹或者文件

         public abstract void remove(folder folder);

         //打开文件或者文件夹--该操作相当于component类型的operation方法

         public abstract void open();

     }

     /// <summary>

     /// 该word文档类就是叶子构件的定义,该类型就相当于是leaf类型,不能在包含子对象

     /// </summary>

     public sealed class word : folder

     {

         //增加文件夹或文件

         public override void add(folder folder)

         {

             throw new exception( "word文档不具有该功能" );

         }

         //删除文件夹或者文件

         public override void remove(folder folder)

         {

             throw new exception( "word文档不具有该功能" );

         }

         //打开文件--该操作相当于component类型的operation方法

         public override void open()

         {

             console.writeline( "打开word文档,开始进行编辑" );

         }

     }

     /// <summary>

     /// sonfolder类型就是树枝构件,由于我们使用的是[透明式],所以add,remove都是从folder类型继承下来的

     /// </summary>

     public class sonfolder : folder

     {

         //增加文件夹或文件

         public override void add(folder folder)

         {

             console.writeline( "文件或者文件夹已经增加成功" );

         }

         //删除文件夹或者文件

         public override void remove(folder folder)

         {

             console.writeline( "文件或者文件夹已经删除成功" );

         }

         //打开文件夹--该操作相当于component类型的operation方法

         public override void open()

         {

             console.writeline( "已经打开当前文件夹" );

         }

     }

     public class program

     {

         static void main()

         {

             folder myword = new word();

             myword.open(); //打开文件,处理文件

             myword.add( new sonfolder()); //抛出异常

             myword.remove( new sonfolder()); //抛出异常

 

             folder myfolder = new sonfolder();

             myfolder.open(); //打开文件夹

             myfolder.add( new sonfolder()); //成功增加文件或者文件夹

             myfolder.remove( new sonfolder()); //成功删除文件或者文件夹

             console.read();

         }

     }

}

以上代码就是[透明式的组合模式]实现,以下代码就是[安全式的组合模式]实现:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

namespace 安全式的组合模式的实现

{

     /// <summary>

     /// 该抽象类就是文件夹抽象接口的定义,该类型就相当于是抽象构件component类型

     /// </summary>

     public abstract class folder //该类型少了容器对象管理子对象的方法的定义,换了地方,在树枝构件也就是sonfolder类型

     {

         //打开文件或者文件夹--该操作相当于component类型的operation方法

         public abstract void open();

     }

     /// <summary>

     /// 该word文档类就是叶子构件的定义,该类型就相当于是leaf类型,不能在包含子对象

     /// </summary>

     public sealed class word : folder  //这类型现在很干净

     {

         //打开文件--该操作相当于component类型的operation方法

         public override void open()

         {

             console.writeline( "打开word文档,开始进行编辑" );

         }

     }

     /// <summary>

     /// sonfolder类型就是树枝构件,现在由于我们使用的是[安全式],所以add,remove都是从此处开始定义的

     /// </summary>

     public abstract class sonfolder : folder //这里可以是抽象接口,可以自己根据自己的情况而定

     {

         //增加文件夹或文件

         public abstract void add(folder folder);

         //删除文件夹或者文件

         public abstract void remove(folder folder);

         //打开文件夹--该操作相当于component类型的operation方法

         public override void open()

         {

             console.writeline( "已经打开当前文件夹" );

         }

     }

     /// <summary>

     /// nextfolder类型就是树枝构件的实现类

     /// </summary>

     public sealed class nextfolder : sonfolder

     {

         //增加文件夹或文件

         public override void add(folder folder)

         {

             console.writeline( "文件或者文件夹已经增加成功" );

         }

         //删除文件夹或者文件

         public override void remove(folder folder)

         {

             console.writeline( "文件或者文件夹已经删除成功" );

         }

         //打开文件夹--该操作相当于component类型的operation方法

         public override void open()

         {

             console.writeline( "已经打开当前文件夹" );

         }

     }

     public class program

     {

         static void main()

         {

             //这是安全的组合模式

             folder myword = new word();

             myword.open(); //打开文件,处理文件

 

             folder myfolder = new nextfolder();

             myfolder.open(); //打开文件夹

             //此处要是用增加和删除功能,需要转型的操作,否则不能使用

             ((sonfolder)myfolder).add( new nextfolder()); //成功增加文件或者文件夹

             ((sonfolder)myfolder).remove( new nextfolder()); //成功删除文件或者文件夹

             console.read();

         }

     }

}

六、组合模式的.net下应用

asp.net中的panel对象就是一个composite对象,而button对象就是leaf对象。button和panel都继承自system.web.ui.control类。它实际上是在panel里面加了一个controls属性,然后controls属性是一个集合属性,它有add和remove方法。

在asp.net中就是这样,每一个控件都有controls属性,也就是说每个控件都是一种容器控件(除了literalcontrol)。这种方式把我们对安全性的担忧,统统放到容器(即asp.net中的controls)中去处理。

这个模式在.net 中最典型的应用就是应用与winforms和web的开发中,在.net类库中,都为这两个平台提供了很多现有的控件,然而system.windows.forms.dll中system.windows.forms.control类就应用了组合模式,因为控件包括label、textbox等这样的简单控件,这些控件可以理解为叶子对象,同时也包括groupbox、datagrid这样复合的控件或者叫容器控件,每个控件都需要调用onpaint方法来进行控件显示,为了表示这种对象之间整体与部分的层次结构,微软把control类的实现应用了组合模式(确切地说应用了透明式的组合模式)。

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!

原文链接:https://HdhCmsTestcnblogs测试数据/xuwendong/p/10381662.html

查看更多关于深入理解Java设计模式之组合模式的详细内容...

  阅读:14次