原創作品,可以轉載,但是請標注出處地址http://www.cnblogs.com/V1haoge/p/6489827.html
組合模式,就是在一個對象中包含其他對象,這些被包含的對象可能是終點對象(不再包含別的對象),也有可能是非終點對象(其內部還包含其他對象,或叫組對象),我們將對象稱為節點,即一個根節點包含許多子節點,這些子節點有的不再包含子節點,而有的仍然包含子節點,以此類推。很明顯,這是樹形結構,終結點叫葉子節點,非終節點(組節點)叫樹枝節點,第一個節點叫根節點。同時也類似於文件目錄的結構形式:文件可稱之為終節點,目錄可稱之為非終節點(組節點)。
1、我們首先來看一個目錄結構的普通實現:
目錄節點:Noder
1 import java.util.ArrayList; 2 import java.util.List; 3 /** 4 * 目錄節點 5 * 包含: 6 * 1、目錄名 7 * 2、下級文件列表 8 * 3、下級目錄列表 9 * 4、新增文件方法 10 * 5、新增目錄方法 11 * 6、顯示下級內容方法 12 */ 13 public class Noder { 14 String nodeName;//目錄名 15 //通過構造器為目錄命名 16 public Noder(String nodeName){ 17 this.nodeName = nodeName; 18 } 19 List<Noder> nodeList = new ArrayList<Noder>();//目錄的下級目錄列表 20 List<Filer> fileList = new ArrayList<Filer>();//目錄的下級文件列表 21 //新增下級目錄 22 public void addNoder(Noder noder){ 23 nodeList.add(noder); 24 } 25 //新增文件 26 public void addFiler(Filer filer){ 27 fileList.add(filer); 28 } 29 //顯示下級目錄及文件 30 public void display(){ 31 for(Noder noder:nodeList){ 32 System.out.println(noder.nodeName); 33 noder.display();//遞歸顯示目錄列表 34 } 35 for(Filer filer:fileList){ 36 filer.display(); 37 } 38 } 39 }
文件節點:Filer
1 /** 2 * 文件節點 3 * 文件節點是終節點,無下級節點 4 * 包含: 5 * 1、文件名 6 * 2、文件顯示方法 7 */ 8 public class Filer { 9 String fileName;//文件名 10 public Filer(String fileName){ 11 this.fileName = fileName; 12 } 13 //文件顯示方法 14 public void display(){ 15 System.out.println(fileName); 16 } 17 }
測試類:Clienter
1 import java.io.File; 2 3 public class Clienter { 4 public static void createTree(Noder node){ 5 File file = new File(node.nodeName); 6 File[] f = file.listFiles(); 7 for(File fi : f){ 8 if(fi.isFile()){ 9 Filer filer = new Filer(fi.getAbsolutePath()); 10 node.addFiler(filer); 11 } 12 if(fi.isDirectory()){ 13 Noder noder = new Noder(fi.getAbsolutePath()); 14 node.addNoder(noder); 15 createTree(noder);//使用遞歸生成樹結構 16 } 17 } 18 } 19 public static void main(String[] args) { 20 Noder noder = new Noder("E://ceshi"); 21 createTree(noder);//創建目錄樹形結構 22 noder.display();//顯示目錄及文件 23 } 24 }
運行結果:
E:\ceshi\目錄1
E:\ceshi\目錄1\目錄3
E:\ceshi\目錄1\文件2.txt
E:\ceshi\目錄2
E:\ceshi\目錄2\文件3.txt
E:\ceshi\文件1.txt
2、組合模式
從上面的代碼中可以看出,我們分別定義了文件節點對象與目錄節點對象,這是因為文件與目錄之間的操作不同,文件沒有下級節點,而目錄可以有下級節點,但是我們能不能這么想:既然文件與目錄都是可以作為一個節點的下級節點而存在,那么我們可不可以將二者抽象為一類對象,雖然二者的操作不同,但是我們可以在實現類的方法實現中具體定義,比如文件沒有新增下級節點的方法,我們就可以在文件的這個方法中拋出一個異常,不做具體實現,而在目錄中則具體實現新增操作。顯示操作二者都有,可以各自實現。而且由於我們將文件與目錄抽象為一個類型,那么結合多態我們可以進行如下實現:
抽象類:Node
1 /** 2 * 將文件與目錄統一看作是一類節點,做一個抽象類來定義這種節點,然后以其實現類來區分文件與目錄,在實現類中分別定義各自的具體實現內容 3 */ 4 public abstract class Node { 5 protected String name;//名稱 6 //構造器賦名 7 public Node(String name){ 8 this.name = name; 9 } 10 //新增節點:文件節點無此方法,目錄節點重寫此方法 11 public void addNode(Node node) throws Exception{ 12 throw new Exception("Invalid exception"); 13 } 14 //顯示節點:文件與目錄均實現此方法 15 abstract void display(); 16 }
文件實現類:Filter
1 /** 2 * 實現文件節點 3 */ 4 public class Filer extends Node { 5 //通過構造器為文件節點命名 6 public Filer(String name) { 7 super(name); 8 } 9 //顯示文件節點 10 @Override 11 public void display() { 12 System.out.println(name); 13 } 14 }
目錄實現類:Noder
1 import java.util.*; 2 /** 3 * 實現目錄節點 4 */ 5 public class Noder extends Node { 6 List<Node> nodeList = new ArrayList<Node>();//內部節點列表(包括文件和下級目錄) 7 //通過構造器為當前目錄節點賦名 8 public Noder(String name) { 9 super(name); 10 } 11 //新增節點 12 public void addNode(Node node) throws Exception{ 13 nodeList.add(node); 14 } 15 //遞歸循環顯示下級節點 16 @Override 17 void display() { 18 System.out.println(name); 19 for(Node node:nodeList){ 20 node.display(); 21 } 22 } 23 }
測試類:Clienter
1 import java.io.File; 2 3 public class Clienter { 4 public static void createTree(Node node) throws Exception{ 5 File file = new File(node.name); 6 File[] f = file.listFiles(); 7 for(File fi : f){ 8 if(fi.isFile()){ 9 Filer filer = new Filer(fi.getAbsolutePath()); 10 node.addNode(filer); 11 } 12 if(fi.isDirectory()){ 13 Noder noder = new Noder(fi.getAbsolutePath()); 14 node.addNode(noder); 15 createTree(noder);//使用遞歸生成樹結構 16 } 17 } 18 } 19 public static void main(String[] args) { 20 Node noder = new Noder("E://ceshi"); 21 try { 22 createTree(noder); 23 } catch (Exception e) { 24 e.printStackTrace(); 25 } 26 noder.display(); 27 } 28 }
E://ceshi E:\ceshi\文件1.txt E:\ceshi\目錄1 E:\ceshi\目錄1\文件2.txt E:\ceshi\目錄1\目錄3 E:\ceshi\目錄2 E:\ceshi\目錄2\文件3.txt
從上述實現中可以看出:所謂組合模式,其實說的是對象包含對象的問題,通過組合的方式(在對象內部引用對象)來進行布局,我認為這種組合是區別於繼承的,而另一層含義是指樹形結構子節點的抽象(將葉子節點與數枝節點抽象為子節點),區別於普通的分別定義葉子節點與數枝節點的方式。
3、組合模式應用場景
這種組合模式正是應樹形結構而生,所以組合模式的使用場景就是出現樹形結構的地方。比如:文件目錄顯示,多及目錄呈現等樹形結構數據的操作。