Java設計模式之《組合模式》及應用場景


原創作品,可以轉載,但是請標注出處地址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、組合模式應用場景

  這種組合模式正是應樹形結構而生,所以組合模式的使用場景就是出現樹形結構的地方。比如:文件目錄顯示,多及目錄呈現等樹形結構數據的操作。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM