1.定义
将对象组合成树形结构以表示“部分-总体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
2.使用场景
(1)表示对象的部分-总体层次结构时。
(2)从一个总体中可以独立出部分模块或功能的场景。
3.UML类图
(1)Component
:抽象根节点,为组合中的对象声明接口。在适当的情况下。实现全部类共同拥有接口的缺省行为。
声明一个接口用于訪问和管理Component的子节点。可在递归结构中定义一个接口,用于訪问一个父节点,并在合适的情况下实现它。
(2)Composite
:定义有子节点的那些枝干节点行为,存储子节点,在Component接口中实现与子节点有关的操作。
(3)Leaf
:在组合中表示叶子节点对象,叶子节点没有子节点。在组合中定义节点对象的行为。
(4)Client
:通过Component接口操纵组合节点的对象。
如图这样的将组合所使用的方法所有定义在抽象类的方式称为透明的组合模式,假设将Component中的Add、Remove、GetChild去除,仅仅在Composite中单独加入。这样的方式称为安全的组合模式。
然而后者违背了依赖倒置原则。
4.简单实现
以文件和目录这种文件系统为例
文件和目录的抽象类:(Component)
public abstract class Dir { /** * 声明一个List成员变量来储存目录下的全部元素 */ protected List
dirs = new ArrayList (); private String name; //当前文件或目录名 public Dir(String name) { this.name = name; } /** * 加入一个文件或目录 * * @param dir 文件或目录 */ public abstract void addDir(Dir dir); /** * 移除一个文件或目录 * * @param dir 文件或目录 */ public abstract void rmDir(Dir dir); /** * 清空目录下全部元素 */ public abstract void clear(); /** * 输出目录目录结构 */ public abstract void print(); /** * 获取目录下全部的文件或目录 * * @return 目录下全部的文件或目录 */ public abstract List getFiles(); /** * 获取文件或目录名 * * @return 文件或目录名 */ public String getName(){ return name; }} - 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
表示目录的类:(Composite)
public class Folder extends Dir{ public Folder(String name) { super(name); } @Override public void addDir(Dir dir) { dirs.add(dir); } @Override public void rmDir(Dir dir) { dirs.remove(dir); } @Override public void clear() { dirs.clear(); } @Override public void print() { System.out.print(getName() + "("); Iterator
iter = dirs.iterator(); while (iter.hasNext()) { Dir dir = iter.next(); dir.print(); if(iter.hasNext()){ System.out.print(", "); } } System.out.print(")"); } @Override public List getFiles() { return dirs; }} - 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
表示目录的类:(Leaf)
public class File extends Dir{ public File(String name) { super(name); } @Override public void addDir(Dir dir) { throw new UnsupportedOperationException("文件对象不支持该操作!
"</span>); } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">rmDir</span>(Dir dir) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> UnsupportedOperationException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"文件对象不支持该操作!"</span>); } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">clear</span>() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> UnsupportedOperationException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"文件对象不支持该操作!
"</span>); } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">print</span>() { System.out.print(getName()); } <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> List<Dir> <span class="hljs-title" style="box-sizing: border-box;">getFiles</span>() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> UnsupportedOperationException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"文件对象不支持该操作!
"</span>); } } </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li></ul>
客户类:
public class Client { public static void main(String[] args) { //构造一个文件夹对象表示C盘根文件夹 Dir diskC = new Folder("C"); //C盘根文件夹下有一个文件Log.txt diskC.addDir(new File("Log.txt")); //C盘根文件夹下有三个文件夹Windows、PerfLogs、Program File Dir dirWin = new Folder("Windows"); //Windows文件夹下有文件explorer.exe dirWin.addDir(new File("explorer.exe")); diskC.addDir(dirWin); //PerfLogs文件夹 Dir dirPer = new Folder("PerfLogs"); //PerfLogs文件夹下有文件null.txt dirPer.addDir(new File("null.txt")); diskC.addDir(dirPer); //Program File文件夹 Dir dirPro = new Folder("Program File"); //Program File文件夹下有文件ftp.txt dirPro.addDir(new File("ftp.txt")); diskC.addDir(dirPro); //打印出文件结构 diskC.print(); }}
- 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
结果:
C(Log.txt, Windows(explorer.exe), PerfLogs(null.txt), Program File(ftp.txt))
- 1
5.Android源代码中的模式实现
1.View和ViewGroup的嵌套组合
View和ViewGroup的结构非常像上面的UML类图,只是View的视图层级使用的是安全的组合模式。ViewGroup有对View的addView、removeView、getChildAt等方法。想必大家也非常熟悉。
6.总结
1.长处
(1)组合模式能够清楚地定义分层次的复杂对象,表示对象的所有或部分层次。他让高层模块忽略了层次的差异。方便对整个层次结构进行控制。
(2)简化了高层模块的代码。
(3)在组合模式中添加新的枝干构件和叶子构件都非常方便。无须对现有类库进行改动,符合“开闭原则”。
(4)对树形结构的控制变得简单。
2.缺点
组合模式不easy限制组合中的构件。由于大多数情况下,它们都来自于同样的抽象层,此时。必须进行类型检查来实现,这个实现过程较为复杂。