组合模式

介绍

也称为整体部分模式,结构型设计模式之一,组合模式比较简单,他将一组相似的对象看作一个对象处理,并根据一个树状结构来组合对象,然后提供一个统一的方法去访问响应的对象,以此忽略掉对象跟对象集合之间的差别。生活中比较典型的例子就是组织结构的树状图。

一个公司有行政部,研发部,同时还有子公司,子公司里也有行政部跟研发部。

在这里虽然总公司跟子公司其本质不一样,但是他们的组织结构是一样的,我们可以把他们看作是一个抽象的公司,在组合模式中我们将这样一个拥有分支的节点称之为枝干构件,位于树状结构顶部的枝干结构比较特殊,我们称之为根结构件,因为其为整个树状结构的始端,同样对于像行政部和研发部这样的没有分支的结构,我们则称之为叶子构件,这样的一个结构就是组合模式的雏形。

标准定义:将对象组合成树形结构以表示”整体-部分”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。

使用场景

  • 表示对象的部分-整体层次结构的时候
  • 从一个整体中能够独立出部分模块或功能的场景

角色介绍

  • Component
  • Composite
  • Leaf
  • Client

Component :抽象根节点,为组合中的对象声明接口。在适当情况下,实现所有类共有接口的缺省的行为。声明一个结构用于访问跟管理Component的子节点。可在递归结构中定一个接口,用于访问一个父节点,并在合适的时候,实现它。

Composite:定义有子节点的那些枝干节点的行为,存储子节点,在Component接口中实现与子节点有关的操作。

Leaf:在组合中表示叶子节点对象,叶子节点没有子节点,在组合中定义节点对象的行为。

Client:通过Component接口操纵组合节点的对象。

组合模式的模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public abstract  class Component {

protected String name;

public Component(String name){
this.name=name;
}


public abstract void doSomething();


public abstract void addChild(Component child);

public abstract void rmvChild(Component child);

public abstract Component getChildren(int index);


}
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
public class Composite extends Component {

private List<Component> components = new ArrayList<>();

public Composite(String name) {
super(name);
}

@Override
public void doSomething() {
System.out.println(name);
if(null!=components){
for(Component c:components){
c.doSomething();
}
}
}

@Override
public void addChild(Component child) {
components.add(child);
}

@Override
public void rmvChild(Component child) {
components.remove(child);
}

@Override
public Component getChildren(int index) {
return components.get(index);
}
}
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
public class Leaf extends Component {

public Leaf(String name) {
super(name);
}

@Override
public void doSomething() {
System.out.println(name);
}

@Override
public void addChild(Component child) {
throw new UnsupportedOperationException("子类型不支持该操作");
}

@Override
public void rmvChild(Component child) {
throw new UnsupportedOperationException("子类型不支持该操作");
}

@Override
public Component getChildren(int index) {
throw new UnsupportedOperationException("子类型不支持该操作");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Client {

public static void main(String[] args){

Component root = new Composite("Root");

Component branch1 = new Composite("Branch1");
Component branch2 = new Composite("Branch2");

Component leaf1 = new Leaf("Leaf1");
Component leaf2 = new Leaf("Leaf2");

branch1.addChild(leaf1);
branch2.addChild(leaf2);

root.addChild(branch1);
root.addChild(branch2);

root.doSomething();


}

}

简单实现

操作系统的文件系统

表示文件或者文件夹的抽象类

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
public abstract class Dir {

//存储文件夹下的所有的元素
protected List<Dir> dirs = new ArrayList<>();

//文件或者文件夹的名字
private String name;

public Dir(String name){
this.name=name;
}

//添加一个文件或者文件夹
public abstract void addDir(Dir dir);

//移除一个文件或者文件夹
public abstract void rmDir(Dir dir);

//清空
public abstract void clear();

//输出文件目录结构
public abstract void print();

//获取文件夹下的所有文件或者文件夹
public abstract List<Dir> getFiles();

//获取文件或者文件夹的名字
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
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();
}

//首先输出自己的名字,然后迭代遍历子元素,调用子元素的print方法输出其目录结构,
// 如果遇到子元素还是个文件夹,那么递归遍历直至所有的输出元素均为文件为止。
@Override
public void print() {

System.out.print(getName()+"(");
Iterator<Dir> iterator = dirs.iterator();
while(iterator.hasNext()){

Dir dir = iterator.next();
dir.print();
if(iterator.hasNext()){
System.out.print(",");
}
}
System.out.print(")");

}

@Override
public List<Dir> 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
public class File extends Dir {

public File(String name) {
super(name);
}

@Override
public void addDir(Dir dir) {
throw new UnsupportedOperationException("文件对象不支持该操作");
}

@Override
public void rmDir(Dir dir) {
throw new UnsupportedOperationException("文件对象不支持该操作");
}

@Override
public void clear() {
throw new UnsupportedOperationException("文件对象不支持该操作");
}

@Override
public void print() {
System.out.print(getName());
}

@Override
public List<Dir> getFiles() {
throw new UnsupportedOperationException("文件对象不支持该操作");
}
}

客户端

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
public class client {

public static void main(String[] args){

Dir diskC = new Folder("C");

diskC.addDir(new File("first.text"));

Dir dirWin = new Folder("windows");
dirWin.addDir(new File("explorer.exe"));

diskC.addDir(dirWin);

Dir dirPer = new Folder("PerfLogs");
dirPer.addDir(new File("null.txt"));

diskC.addDir(dirPer);

Dir dirPro = new Folder("Program File");
dirPro.addDir(new File("ftp.txt"));

diskC.addDir(dirPro);

diskC.print();


}
}

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器