组件模式
概念
一个东西,既可以作为其他容器中的一项,同时自己也可以作为容器存储其他东西,其他东西可以是普通的内容,内容不能作为容器了,也可以是容器,而这个东西就是抽象的最上层。
角色
- Leaf
叶子,即内容,最小的原子 - Composite
容器,可以存储容器和内容 - Component
容器和内容被视作同一超类下的子类,这个超类就是组件 - Client
调用者
案例
模拟文件系统
- Leaf
File(文件:实类) - Composite
Folder(文件夹:实类),文件夹中可以加入文件或者子文件夹 - Component
Entry(条目:抽象类,文件,文件夹都算作是条目) - Client
调用者(Main.java)
Entry
- 条目都有名字,因此抽象条目直接具备name属性
- 至于条目的大小,文件是自身的大小,文件夹则是目录下所有文件大小的集合,逻辑上不太一样,还是交给子类去拓展吧,这里只声明一个获取size的方法
- list方法则是打印条目内所有条目信息(带上路径和条目名)
package com.example.composite.example_folder;
public abstract class Entry {
protected String name;
public Entry(String name) {
this.name = name;
}
public String getName(){
return name;
}
public abstract int getSize();
public void list(){
list("");
}
protected abstract void list(String prefix); //路径前缀
@Override
public String toString(){
return getName() + "(" + getSize() + " kb)";
}
}
File
文件:
- 新增size属性,构造时给文件设定大小
- list方法,打印自己的条目信息,也就是name和size,带上单位kb
package com.example.composite.example_folder;
public class File extends Entry {
private int size;
public File(String name, int size) {
super(name);
this.size = size;
}
@Override
public int getSize() {
return size;
}
@Override
protected void list(String prefix) {
System.out.println(prefix + "/" + this);
}
}
Folder
文件夹:
- 私有一个条目列表
- 有一个add方法,往自己的条目列表加入一个条目
- 获取size方法,遍历条目列表,累加所有条目的size,如果某个子条目也是文件夹,就递归下去获取size,如果是文件,就能直接拿到size
- list方法,遍历打印条目列表中每个条目的信息,原理类似获取size
package com.example.composite.example_folder;
import java.util.ArrayList;
public class Folder extends Entry {
private ArrayList<Entry> entries = new ArrayList();
public Folder(String name) {
super(name);
}
@Override
public int getSize() {
int size = 0;
for ( Entry entry: entries) {
size += entry.getSize();
}
return size;
}
public Entry add(Entry entry) {
entries.add(entry);
return this;
}
@Override
protected void list(String prefix) {
System.out.println(prefix + "/" + this);
for ( Entry entry: entries) {
entry.list(prefix + "/" + name);
}
}
}
Main.java
package com.example.composite;
import com.example.composite.example_folder.File;
import com.example.composite.example_folder.Folder;
public class Main {
public static void main(String[] args) {
Folder folder_root = new Folder("root");
Folder folder_bin = new Folder("bin");
folder_root.add(folder_bin);
Folder folder_vi = new Folder("vi");
folder_bin.add(folder_vi);
Folder folder_latex = new Folder("latex");
folder_bin.add(folder_latex);
Folder folder_tmp = new Folder("tmp");
folder_root.add(folder_tmp);
Folder folder_usr = new Folder("usr");
folder_root.add(folder_usr);
Folder folder_evanp = new Folder("evanp");
folder_usr.add(folder_evanp);
File file_readme_md = new File("readme.md", 200);
folder_evanp.add(file_readme_md);
folder_root.list();
}
}
Output
D:\Develop-Environment\Java\jdk-1.8\bin\java.exe ...
/root(200 kb)
/root/bin(0 kb)
/root/bin/vi(0 kb)
/root/bin/latex(0 kb)
/root/tmp(0 kb)
/root/usr(200 kb)
/root/usr/evanp(200 kb)
/root/usr/evanp/readme.md(200 kb)
Process finished with exit code 0
应用场景
使用Composite模式可以使得容器与内容具有一致性,即将多个对象结合在一起,当作一个对象处理,访问容器的内容时,自然的形成了递归结构,通常来说,树形结构都使用Composite模式。