设计模式学习笔记——组合(Composite)模式
@(设计模式)[设计模式, 组合模式, composite]
基本介绍
组合模式能够使容器与内容具有一致性,创造出递归结构。比如文件夹和文件,树形结构中的叶子节点和枝干节点。都可以用组合模式实现。
组合案例
类图
实现代码
Entry抽象类
package com.pc.composite.example;
/**
* 条目抽象类
* Created by Switch on 2017-02-21.
*/
public abstract class Entry {
/**
* 获取名字
*
* @return 名字
*/
public abstract String getName();
/**
* 获取占用空间
*
* @return 占用空间
*/
public abstract int getSize();
/**
* 添加
*
* @param entry 条目对象
* @return 返回文件夹对象
* @throws FileTreatmentException 文件处理异常
*/
public Entry add(Entry entry) throws FileTreatmentException {
throw new FileTreatmentException("只有文件夹才能添加条目!");
}
/**
* 使用默认前缀,显示目录条目
*/
public void printList() {
printList("");
}
/**
* 指定前缀,显示目录条目
*
* @param prefix 前缀
*/
protected abstract void printList(String prefix);
@Override
public String toString() {
return this.getName() + " (" + this.getSize() + ")";
}
}
File类
package com.pc.composite.example;
/**
* 文件类
* Created by Switch on 2017-02-21.
*/
public class File extends Entry {
/**
* 文件名
*/
private String name;
/**
* 文件占用空间
*/
private int size;
/**
* 构造方法,传入文件名和文件占用空间
*
* @param name 文件名
* @param size 文件占用空间
*/
public File(String name, int size) {
this.name = name;
this.size = size;
}
@Override
public String getName() {
return this.name;
}
@Override
public int getSize() {
return this.size;
}
@Override
protected void printList(String prefix) {
System.out.println(prefix + "/" + this);
}
}
Directory类
package com.pc.composite.example;
import java.util.ArrayList;
import java.util.List;
/**
* 文件夹类
* Created by Switch on 2017-02-21.
*/
public class Directory extends Entry {
/**
* 文件夹名
*/
private String name;
/**
* 文件夹中的条目集合
*/
private List<Entry> entries = new ArrayList<>();
/**
* 构造方法,传入文件夹名
*
* @param name 文件夹名
*/
public Directory(String name) {
this.name = name;
}
@Override
public String getName() {
return this.name;
}
@Override
public int getSize() {
int size = 0;
for (Entry entry : entries) {
size += entry.getSize();
}
return size;
}
@Override
public Entry add(Entry entry) {
this.entries.add(entry);
return this;
}
@Override
protected void printList(String prefix) {
System.out.println(prefix + "/" + this);
for (Entry entry : entries) {
// 打印文件夹下的文件列表,以文件夹前缀,文件名作为前缀
entry.printList(prefix + "/" + this.name);
}
}
}
FileTreatmentException类
package com.pc.composite.example;
/**
* 文件处理异常
* Created by Switch on 2017-02-21.
*/
public class FileTreatmentException extends RuntimeException {
public FileTreatmentException() {
}
public FileTreatmentException(String message) {
super(message);
}
}
测试类
package com.pc.composite.example.test;
import com.pc.composite.example.Directory;
import com.pc.composite.example.File;
import com.pc.composite.example.FileTreatmentException;
import org.junit.Test;
/**
* Entry Tester.
*
* @author Switch
* @version 1.0
*/
public class EntryTest {
/**
* 测试微型文件系统
*/
@Test
public void testEntry() {
try {
System.out.println("添加文件和文件夹:");
System.out.println("Making root entries...");
Directory rootDir = new Directory("root");
Directory binDir = new Directory("bin");
Directory etcDir = new Directory("etc");
Directory usrDir = new Directory("usr");
rootDir.add(binDir);
rootDir.add(etcDir);
rootDir.add(usrDir);
binDir.add(new File("java", 5000));
binDir.add(new File("javac", 10000));
rootDir.printList();
System.out.println();
System.out.println("接着添加文件和文件夹:");
System.out.println("Making user entries...");
Directory switchvov = new Directory("switchvov");
Directory kity = new Directory("kity");
Directory tom = new Directory("tom");
Directory bob = new Directory("bob");
usrDir.add(switchvov);
usrDir.add(kity);
usrDir.add(tom);
usrDir.add(bob);
switchvov.add(new File("readme.txt", 1000));
switchvov.add(new File("hello.txt", 400));
kity.add(new File("find.sh", 5000));
tom.add(new File("rehash.sh", 4000));
tom.add(new File("index.html", 15400));
rootDir.printList();
} catch (FileTreatmentException e) {
e.printStackTrace();
}
}
}
运行结果
添加文件和文件夹:
Making root entries...
/root (15000)
/root/bin (15000)
/root/bin/java (5000)
/root/bin/javac (10000)
/root/etc (0)
/root/usr (0)
接着添加文件和文件夹:
Making user entries...
/root (40800)
/root/bin (15000)
/root/bin/java (5000)
/root/bin/javac (10000)
/root/etc (0)
/root/usr (25800)
/root/usr/switchvov (1400)
/root/usr/switchvov/readme.txt (1000)
/root/usr/switchvov/hello.txt (400)
/root/usr/kity (5000)
/root/usr/kity/find.sh (5000)
/root/usr/tom (19400)
/root/usr/tom/rehash.sh (4000)
/root/usr/tom/index.html (15400)
/root/usr/bob (0)
组合模式中的角色
Leaf(树叶)
表示”内容”的角色。在该角色中不能放入其他对象。在案例中,由File
类扮演此角色。
Composite(复合物)
表示容器的角色。可以在其中放入Leaf
角色和Composite
角色。在案例中,由Directory
类扮演此角色。
Component
使Leaf
角色和Composite
角色具有一致性的角色。Composite
角色是Leaf
角色和Composite
角色的父类。在案例中,由Entry
类扮演此角色。
Client
使用Composite
模式的角色。在案例中,由测试类扮演此角色。
Composite
模式的类图如下图所示。在该图中,可以将Composite
角色与它内部的Component
角色(即Leaf
角色或Composite
角色)看成是父亲与孩子们的关系。getChild
方法的作用是从Component
角色获取这些”孩子们”。
类图
GitHub:DesignPatternStudy
——————参考《图解设计模式》