组合模式-Composite
Composite模式使得用户对单个对象和组合对象的使用具有一致性.
以<<图解设计模式>>的文件例子来说: 文件夹是文件的组合, 文件是单个对象, 文件夹是多个文件的组合. 不过对用户来说, 无论是文件还是文件夹, 他希望使用一个统一的方法来管理他们.这就需要将他们再次抽象出来.
解读一下这个类图就明白了:
1. 文件是一个组件
2. 文件夹也是一个组件
3. 文件夹里有很多组件:
3.1 文件夹里可以有文件
3.2 文件夹里可以有文件夹
Component抽象类
这是文件 文件夹的抽象定义类--组件类
/** * 这里是文件/文件夹 的统一抽象类 "组件类" */ public abstract class Component { /** * parent是父组件的指针, 也就是本例子中的"父级目录" */ protected Component parent; /** * 获取组件名字 */ public abstract String getName(); /** * 获取组件的大小 */ public abstract int getSize(); /** * @implNote 向一个组件中添加一个组件. * @implSpec 组合模式中的叶子(Leaf)节点不可以使用这个方法, 用例子说明的话: * 一个文件不可以添加一个文件或文件夹, 只能是文件夹来添加文件或文件夹 */ public Component add(Component entry) { throw new RuntimeException("不支持此类操作..."); } public void printList() { printList(""); } protected abstract void printList(String prefix); /** * 获取绝对路径 */ public String getFullName() { StringBuilder fullName = new StringBuilder(); Component entry = this; do { fullName.insert(0, "/" + entry.getName()); entry = entry.parent; } while (entry != null); return fullName.toString(); } /** * 其中的getSize() 会被子类重写, 因为文件大小可以很容易知道, 但是文件夹大小需要递归计算 */ @Override public String toString() { return getName() + " (" + getSize() + ")"; } }
MyFile类
MyFile类在组合模式中是Leaf(叶子)节点, 因为他不会包含其他组件.
我们可以把组件模式想象成一颗树(绿色表示文件夹, 橙色表示文件):
组合模式的叶子节点指的是文件节点, 因为文件永远也不会有子节点.
而绿的c1节点虽然现在是叶子节点, 但是如果给c1文件夹添加了一个文件的话, 他就不再是叶子节点了.
组合模式里无法继续添加子节点的就被称作Leaf(叶子)
上面那个树, 等价于下图:
public class MyFile extends Component { private String name; private int size; public MyFile(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.toString()); } }
MyDirectory类
MyDirectory类作为一个文件夹, 可以包含其他组件(文件/文件夹)
public class MyDirectory extends Component { private String name; private ArrayList<Component> substance = new ArrayList<>(); public MyDirectory(String name) { this.name = name; } @Override public String getName() { return this.name; } /** * 获取文件夹的大小: * 1. size一开始是0 * 2. 如果是文件, 那么直接把文件的大小加到size上 * 3. 如果是文件夹, 那么就递归地查出该文件夹的大小, 然后加到size上. */ @Override public int getSize() { int size = 0; for (Component entry : substance) { size += entry.getSize(); } return size; } /** * 像一个文件夹中添加一个文件或文件夹 */ @Override public Component add(Component entry) { substance.add(entry); entry.parent = this; return this; } /** * 1. 打印当前目录的路径 * 2. 然后打印出子目录, 子文件的路径 * 3. 子目录再打印子子目录/子子文件的路径...如此递归 */ @Override protected void printList(String prefix) { System.out.println(prefix + "/" + this.toString()); for (Component entry : substance) { entry.printList(prefix + "/" + name); } } }
Main
用于测试运行
public class Main { public static void main(String[] args) { /* 本例子目录结构如下: 一级目录 二级目录 三级目录 a1 |-------b1 |-------b2 | a2 |-------c1 |-------Composite.java |-------king.python |-------c2 */ MyDirectory a1 = new MyDirectory("a1"); MyDirectory a2 = new MyDirectory("a2"); MyDirectory b1 = new MyDirectory("b1"); MyDirectory b2 = new MyDirectory("b2"); a1.add(b1).add(b2); MyDirectory c1 = new MyDirectory("c1"); MyDirectory c2 = new MyDirectory("c2"); a2.add(c1).add(c2); MyFile java = new MyFile("Composite.java", 100); MyFile python = new MyFile("king.python", 214); c1.add(java).add(python); /*-****** getFullName() ************-*/ System.out.println(java.getFullName()); System.out.println(python.getFullName()); System.out.println(""); /*-****** getFullName() ************-*/ a1.printList(); System.out.println("-----"); a2.printList(); } }
原文地址:https://www.cnblogs.com/noKing/p/9020119.html
时间: 2024-10-30 02:00:53