1、概念
將對象以樹形結構組織起來,以達成“部分-整體”的層次機構,使得客戶端對單個對象和組合對象的使用具有一致性。
是用於把一組相似的對象當作一個單一的對象。組合模式依據樹形結構來組合對象,用來表示部分以及整體層次。這種類型的設計模式屬於結構型模式,它創建了對象組的樹形結構。
這種模式創建了一個包含自己對象組的類。該類提供了修改相同對象組的方式。
2、使用場景
部分、整體場景,如樹形菜單,文件、文件夾的管理。
- 需要表示一個對象整體或部分層次
- 希望用戶忽略組合對象與單個對象的不同,用戶將統一地使用組合結構中的所有對象。
3、如何使用
樹枝和葉子實現統一接口,樹枝內部組合該接口。
4、UML結構圖分析
5、實際代碼分析
例:文件與文件夾的關係
先進行普通的實現方式
//文件類
public class File {
public String name;
public File(String name) {
this.name = name;
}
/**
* 操作方法
* @return
*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void watch() {
System.out.println("文件名"+getName()+"文件數目");
}
}
//文件夾類
public class Folder{
public String name;
private List<File> mFileList;
public Folder(String name) {
mFileList = new ArrayList<>();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void watch() {
StringBuilder sb = new StringBuilder();
for(File f:mFileList){
sb.append(f.name);
}
System.out.println("文件名"+getName()+"文件數目"+ mFileList.size()+"名字"+sb.toString());
}
public void add(File file) {
mFileList.add(file);
}
public void remove(File file) {
mFileList.remove(file);
}
public File getChild(int pos) {
return mFileList.get(pos);
}
}
//運行
File file = new File("hehe");
Folder folder = new Folder("heere");
folder.add(file);
folder.watch();
文件和文件夾作爲兩個類來進行操作,將文件類進行添加文件,但是呢?如果文件夾下添加文件夾該咋辦呢?就需要再創建一個list來存放文件夾,這樣大家都是節點,爲啥搞得這麼複雜呢?既然存在上下級節點的問題,咱們就抽象爲一個抽象類,用抽象類作爲節點,子類就是文件夾和文件。
//將文件與文件夾統一看作是一類節點,做一個抽象類來定義這種節點,然後以其實現類來區分文件與目錄,在實現類中分別定義各自的具體實現內容,把組合方法寫到這個節點類中
public abstract class File {
public String name;
public File(String name) {
this.name = name;
}
/**
* 操作方法
* @return
*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract void watch();
/**
* 組合方法
* @param file
*/
public void add(File file){
throw new UnsupportedOperationException();
}
public void remove(File file){
throw new UnsupportedOperationException();
}
public File getChild(int pos){
throw new UnsupportedOperationException();
}
}
public class Folder extends File{
private List<File> mFileList;
public Folder(String name) {
super(name);
mFileList = new ArrayList<>();
}
@Override
public void watch() {
StringBuilder sb = new StringBuilder();
for(File f:mFileList){
sb.append(f.name);
}
System.out.println("文件名"+getName()+"文件數目"+ mFileList.size()+"名字"+sb.toString());
}
@Override
public void add(File file) {
mFileList.add(file);
}
@Override
public void remove(File file) {
mFileList.remove(file);
}
@Override
public File getChild(int pos) {
return mFileList.get(pos);
}
}
public class TestFile extends File {
public TestFile(String name) {
super(name);
}
@Override
public void watch() {
System.out.println("文件名"+getName()+"文件數目");
}
}
//運行
TestFile file = new TestFile("hehe");
Folder folder = new Folder("heere");
folder.add(file);
folder.watch();
folder.getChild(0).watch();
這種組合模式正是應樹形結構而生,所以組合模式的使用場景就是出現樹形結構的地方。比如:文件目錄顯示,多及目錄呈現等樹形結構數據的操作。
安全組合模式(簡化)如下code
//將文件與文件夾統一看作是一類節點,做一個抽象類來定義這種節點,然後以其實現類來區分文件與目錄,在實現類中分別定義各自的具體實現內容,把組合方法寫到這個節點類中
public abstract class File {
public String name;
public File(String name) {
this.name = name;
}
/**
* 操作方法
* @return
*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract void watch();
}
public class Folder extends File{
private List<File> mFileList;
public Folder(String name) {
super(name);
mFileList = new ArrayList<>();
}
@Override
public void watch() {
StringBuilder sb = new StringBuilder();
for(File f:mFileList){
sb.append(f.name);
}
System.out.println("文件名"+getName()+"文件數目"+ mFileList.size()+"名字"+sb.toString());
}
public void add(File file) {
mFileList.add(file);
}
public void remove(File file) {
mFileList.remove(file);
}
public File getChild(int pos) {
return mFileList.get(pos);
}
}
public class TestFile extends File {
public TestFile(String name) {
super(name);
}
@Override
public void watch() {
System.out.println("文件名"+getName()+"文件數目");
}
}
//運行
TestFile file = new TestFile("hehe");
Folder folder = new Folder("heere");
folder.add(file);
folder.watch();
folder.getChild(0).watch();
安全組合模式分工就很明確了。它還有一個好處就是當我們add/remove的時候,我們能知道具體的類是什麼了,而透明組合模式就得在運行時去判斷,比較麻煩。
優點:
- 高層模塊調用簡單
- 節點自由增加
缺點:
- 在使用組合模式時,其葉子和樹枝的聲明都是實現類,而不是接口,違反了依賴倒置原則。
- 葉子類型不能控制。比如我想控制ViewGroup添加的View必須爲TextView的時候,約束起來就很麻煩。特別是類型多的時候。