设计模式--组合模式
1 概述
1.1 定义
组合模式(Composite Design)将对象组合成树形结构来表现"整体/部分"层次结构。组合能让客户端以一致的方式处理个别对象以及对象组合。
1.2 应用场景
维护和展示部分-整体的层次结构,如Unix中的树形文件系统。
客户端可以忽略复杂的层次结构,使用统一的方式去操作层次结构中的所有对象,也可以使用组合模式。
简单的可以说:树状结构并且其各个节点(根、枝、叶)有共同的行为,就可以使用组合模式。
1.3 类图
组合模式涉及的角色如下:
- Component抽象组件角色:定义参加组合对象的方法(一些方法Leaf不实现)。
- Composite组合角色:作用是与Leaf(树叶)节点形成一个树形结构。
- Leaf叶子角色:是遍历的最小单位。
2 详解
1 public abstract class Component { 2 // 个体与整体都具有的行为 3 public void operate(){ 4 System.out.println("Common operation"); 5 } 6 // 添加一个叶子或者组合 7 public abstract void add(Component component) throws UnsupportedOperationException; 8 9 // 移除一个叶子或者组合 10 public abstract boolean remove(Component component) throws UnsupportedOperationException; 11 12 // 获得其分支下的所有叶子和组合 13 public abstract List<Component> getChildren() throws UnsupportedOperationException; 14 } 15 16 public class Composite extends Component { 17 // 容器构件 18 private List<Component> componentList = new ArrayList<>(); 19 20 @Override 21 public void add(Component component) throws UnsupportedOperationException { 22 componentList.add(component); 23 } 24 25 @Override 26 public boolean remove(Component component) throws UnsupportedOperationException { 27 return componentList.remove(component); 28 } 29 30 @Override 31 public List<Component> getChildren() throws UnsupportedOperationException { 32 return componentList; 33 } 34 } 35 36 public class Leaf extends Component { 37 @Override 38 public void add(Component component) throws UnsupportedOperationException { 39 throw new UnsupportedOperationException(); 40 } 41 42 @Override 43 public boolean remove(Component component) throws UnsupportedOperationException { 44 throw new UnsupportedOperationException(); 45 } 46 47 @Override 48 public List<Component> getChildren() throws UnsupportedOperationException { 49 throw new UnsupportedOperationException(); 50 } 51 } 52 53 public class Client { 54 public static void main(String[] args) { 55 Component root = new Composite(); 56 Component brance = new Composite(); 57 Component leaf = new Leaf(); 58 root.add(brance); 59 brance.add(leaf); 60 } 61 // 递归遍历该树 62 public static void display(Component root) { 63 for(Component component : root.getChildren()) { 64 // 树枝节点 65 if(component instanceof Composite) { 66 display(component); 67 }else { 68 // 叶子节点 69 component.operate(); 70 } 71 } 72 } 73 }
3 应用
简单的模拟unix的文件系统
1 public abstract class IFile { 2 private String name; 3 // 父类IFile 4 private IFile parentIFile; 5 6 IFile(String name) { 7 this.name = name; 8 } 9 10 public String getName(){ 11 return name; 12 } 13 14 // 删除其自己 15 public abstract boolean remove(); 16 17 // 获得其分支文件或者文件名 18 public abstract IFile getIFile(String name) throws UnsupportedOperationException; 19 20 // 创建文件 21 public abstract void createFile(String name) throws UnsupportedOperationException; 22 23 // 创建文件夹 24 public abstract void createFolder(String name) throws UnsupportedOperationException; 25 26 // 删除其分支文件 27 public abstract boolean deleteFile(String name) throws UnsupportedOperationException; 28 29 // 删除其分支文件夹 30 public abstract boolean deleteFolder(String name) throws UnsupportedOperationException; 31 32 // 获得其分支的文件或文件夹 33 public abstract Set<IFile> getChildren() throws UnsupportedOperationException; 34 35 // 设置父类文件 36 public void setParentIFile(IFile parentIFile) { 37 this.parentIFile = parentIFile; 38 } 39 40 // 获得父类文件 41 public IFile getParentIFile() { 42 return parentIFile; 43 } 44 45 @Override 46 public boolean equals(Object obj) { 47 if(obj == this) { 48 return true; 49 } 50 if(obj instanceof IFile) { 51 IFile iFile = (IFile) obj; 52 return Objects.equals(iFile.getName(), getName()); 53 } 54 return false; 55 } 56 57 @Override 58 public int hashCode() { 59 return name.hashCode(); 60 } 61 62 @Override 63 public String toString() { 64 return name; 65 } 66 } 67 68 public class Folder extends IFile { 69 private Set<IFile> files = new HashSet<>(); 70 71 Folder(String name) { 72 super(name); 73 } 74 75 @Override 76 public boolean remove() { 77 System.out.println("删除文件夹: " + getName()); 78 IFile parent = getParentIFile(); 79 return parent.deleteFolder(getName()); 80 } 81 82 @Override 83 public IFile getIFile(String name) throws UnsupportedOperationException { 84 for(IFile iFile : files) { 85 if(iFile.getName().equals(name)) { 86 return iFile; 87 } 88 } 89 return null; 90 } 91 92 @Override 93 public void createFile(String name) throws UnsupportedOperationException { 94 IFile file = new File(name); 95 file.setParentIFile(this); 96 files.add(file); 97 } 98 99 @Override 100 public void createFolder(String name) throws UnsupportedOperationException { 101 IFile fileFolder = new Folder(name); 102 fileFolder.setParentIFile(this); 103 files.add(fileFolder); 104 } 105 106 @Override 107 public boolean deleteFile(String name) throws UnsupportedOperationException { 108 return files.remove(new File(name)); 109 } 110 111 @Override 112 public boolean deleteFolder(String name) throws UnsupportedOperationException { 113 return files.remove(new Folder(name)); 114 } 115 116 @Override 117 public Set<IFile> getChildren() throws UnsupportedOperationException { 118 return files; 119 } 120 } 121 122 public class File extends IFile { 123 124 File(String name) { 125 super(name); 126 } 127 128 @Override 129 public boolean remove() { 130 System.out.println("删除文件夹: " + getName()); 131 IFile parent = getParentIFile(); 132 return parent.deleteFile(getName()); 133 } 134 135 @Override 136 public void createFile(String name) throws UnsupportedOperationException { 137 throw new UnsupportedOperationException(); 138 } 139 140 @Override 141 public void createFolder(String name) throws UnsupportedOperationException { 142 throw new UnsupportedOperationException(); 143 } 144 145 @Override 146 public boolean deleteFile(String name) throws UnsupportedOperationException { 147 throw new UnsupportedOperationException(); 148 } 149 150 @Override 151 public boolean deleteFolder(String name) throws UnsupportedOperationException { 152 throw new UnsupportedOperationException(); 153 } 154 155 @Override 156 public Set<IFile> getChildren() throws UnsupportedOperationException { 157 throw new UnsupportedOperationException(); 158 } 159 160 @Override 161 public IFile getIFile(String name) throws UnsupportedOperationException { 162 throw new UnsupportedOperationException(); 163 } 164 } 165 166 public class Client { 167 public static void main(String[] args) { 168 IFile root = new Folder("/"); 169 root.createFolder("user"); 170 root.createFolder("net"); 171 root.createFile("root.txt"); 172 173 IFile user = root.getIFile("user"); 174 user.createFolder("picture"); 175 user.createFolder("music"); 176 IFile picture = user.getIFile("picture"); 177 picture.createFile("flower.png"); 178 picture.createFile("book.png"); 179 IFile music = user.getIFile("music"); 180 music.createFile("hello.mp3"); 181 182 IFile net = root.getIFile("net"); 183 net.createFolder("config"); 184 net.createFile("setting.txt"); 185 186 display(null, root); 187 } 188 // 递归遍历 189 public static void display(String prefix, IFile root) { 190 if(prefix == null) { 191 prefix = ""; 192 } 193 System.out.println(prefix + root); 194 for(IFile iFile : root.getChildren()) { 195 if(iFile instanceof Folder) { 196 display(prefix + "--", iFile); 197 } 198 if(iFile instanceof File) { 199 System.out.println(prefix + "--" + iFile); 200 } 201 } 202 } 203 }output: 204 / 205 --root.txt 206 --net 207 ----setting.txt 208 ----config 209 --user 210 ----music 211 ------hello.mp3 212 ----picture 213 ------flower.png 214 ------book.png