亚洲精品不卡久久久久久_色视频线观看在线 _妽妽夹得我好舒服_国产真人一级a爱做片高潮_亚洲aⅴ无码专区在线观看q

當前位置: 首頁 >快訊 > 正文

組合模式詳解 環(huán)球關(guān)注

2023-06-27 02:52:30 來源:博客園
簡介

組合模式(Composite)是針對由多個節(jié)點對象(部分)組成的樹形結(jié)構(gòu)的對象(整體)而發(fā)展出的一種結(jié)構(gòu)型設(shè)計模式,它能夠使客戶端在操作整體對象或者其下的每個節(jié)點對象時做出統(tǒng)一的響應(yīng),保證樹形結(jié)構(gòu)對象使用方法的一致性,使客戶端不必關(guān)注對象的整體或部分,最終達到對象復(fù)雜的層次結(jié)構(gòu)與客戶端解耦的目的。

組合模式的核心思想是將對象看作是一個樹形結(jié)構(gòu),其中每個節(jié)點可以是一個單獨的對象(葉子節(jié)點)或者一個包含其他節(jié)點的容器(組合節(jié)點)。葉子節(jié)點和組合節(jié)點都實現(xiàn)了相同的接口,這樣客戶端就可以對它們進行一致的操作,而不需要關(guān)心它們的具體類型。


(資料圖片僅供參考)

組合模式有以下幾個角色:

Component(組件接口):所有復(fù)合節(jié)點與葉節(jié)點的高層抽象,定義出需要對組件操作的接口標準。對應(yīng)本章例程中的抽象節(jié)點類,具體使用接口還是抽象類需根據(jù)具體場景而定。Composite(復(fù)合組件):包含多個子組件對象(可以是復(fù)合組件或葉端組件)的復(fù)合型組件,并實現(xiàn)組件接口中定義的操作方法。對應(yīng)本章例程中作為“根節(jié)點/枝節(jié)點”的文件夾類。Leaf(葉端組件):不包含子組件的終端組件,同樣實現(xiàn)組件接口中定義的操作方法。對應(yīng)本章例程中作為“葉節(jié)點”的文件類。Client(客戶端):按所需的層級關(guān)系部署相關(guān)對象并操作組件接口所定義的接口,即可遍歷樹結(jié)構(gòu)上的所有組件。好處和壞處

組合模式的好處有:

可以將對象組合成樹形結(jié)構(gòu),表示整體-部分的層次關(guān)系,符合人們的直覺。可以統(tǒng)一處理單個對象和對象組合,簡化了客戶端的代碼邏輯,提高了系統(tǒng)的可復(fù)用性。可以遵循開閉原則,擴展性高,增加新的節(jié)點類型時不需要修改原有代碼。

組合模式的壞處有:

可以使設(shè)計變得過于抽象,不利于理解和維護??梢赃`反單一職責(zé)原則,讓葉子節(jié)點和組合節(jié)點具有相同的接口,導(dǎo)致葉子節(jié)點出現(xiàn)不必要的方法??梢詫?dǎo)致遞歸調(diào)用過深,影響系統(tǒng)的性能。應(yīng)用場景

組合模式是一種將對象組合成樹形結(jié)構(gòu)的設(shè)計模式,它可以表示整體-部分的層次關(guān)系,并且提供了一致的接口來操作單個對象和對象組合。應(yīng)用場景有:

當需要表示一個對象整體與部分的層次結(jié)構(gòu)時,可以使用組合模式來實現(xiàn)樹形結(jié)構(gòu)。例如,文件系統(tǒng)中的文件與文件夾、組織機構(gòu)中的部門與員工、商品分類中的類別與商品等。當需要統(tǒng)一處理單個對象和對象組合時,可以使用組合模式來實現(xiàn)多態(tài)性。例如,圖形界面中的簡單控件與容器控件、菜單系統(tǒng)中的菜單項與子菜單、報表系統(tǒng)中的單元格與表格等。當需要將對象的創(chuàng)建和使用分離時,可以使用組合模式來實現(xiàn)依賴注入。例如,Spring框架中的Bean對象與BeanFactory對象、測試框架中的測試用例與測試套件等。Java 代碼示例

假設(shè)我們有一個文件系統(tǒng),其中有兩種類型的文件:文本文件和文件夾。文本文件是葉子節(jié)點,文件夾是組合節(jié)點,可以包含其他文件。我們想要使用組合模式來實現(xiàn)文件系統(tǒng)的層次結(jié)構(gòu),并且提供一個打印文件路徑的方法。代碼如下:

定義抽象組件

public interface File {    // 獲取文件名稱    String getName();    // 添加子文件    void add(File file);    // 刪除子文件    void remove(File file);    // 獲取子文件    List getChildren();    // 打印文件路徑    void printPath(int space);}

定義葉子節(jié)點

public class TextFile implements File {    private String name;    public TextFile(String name) {        this.name = name;    }    @Override    public String getName() {        return name;    }    @Override    public void add(File file) {        throw new UnsupportedOperationException("Text file cannot add child file");    }    @Override    public void remove(File file) {        throw new UnsupportedOperationException("Text file cannot remove child file");    }    @Override    public List getChildren() {        throw new UnsupportedOperationException("Text file has no child file");    }    @Override    public void printPath(int space) {        StringBuilder sp = new StringBuilder();        for (int i = 0; i < space; i++) {            sp.append(" ");        }        System.out.println(sp + name);    }}

定義組合節(jié)點

public class Folder implements File {    private String name;    private List children;    public Folder(String name) {        this.name = name;        children = new ArrayList<>();    }    @Override    public String getName() {        return name;    }    @Override    public void add(File file) {        children.add(file);    }    @Override    public void remove(File file) {        children.remove(file);    }    @Override    public List getChildren() {        return children;    }    @Override    public void printPath(int space) {        StringBuilder sp = new StringBuilder();        for (int i = 0; i < space; i++) {            sp.append(" ");        }        System.out.println(sp + name);        space += 2;        for (File child : children) {            child.printPath(space);        }    }}

客戶端代碼

public class Client {    public static void main(String[] args) {        // 創(chuàng)建一個根文件夾,并添加兩個文本文件和一個子文件夾        File root = new Folder("root");        root.add(new TextFile("a.txt"));        root.add(new TextFile("b.txt"));        File subFolder = new Folder("subFolder");        root.add(subFolder);        // 在子文件夾中添加兩個文本文件        subFolder.add(new TextFile("c.txt"));        subFolder.add(new TextFile("d.txt"));        // 打印根文件夾的路徑        root.printPath(0);    }}

輸出結(jié)果:

root  a.txt  b.txt  subFolder    c.txt    d.txt
Go 代碼示例
package main// importing fmt packageimport ("fmt")// IComposite interfacetype IComposite interface {perform()}// Leaflet structtype Leaflet struct {name string}// Leaflet class method performfunc (leaf *Leaflet) perform() {fmt.Println("Leaflet " + leaf.name)}// Branch structtype Branch struct {leafs    []Leafletname     stringbranches []Branch}// Branch class method performfunc (branch *Branch) perform() {fmt.Println("Branch: " + branch.name)for _, leaf := range branch.leafs {leaf.perform()}for _, branch := range branch.branches {branch.perform()}}// Branch class method add leafletfunc (branch *Branch) add(leaf Leaflet) {branch.leafs = append(branch.leafs, leaf)}//Branch class method addBranch branchfunc (branch *Branch) addBranch(newBranch Branch) {branch.branches = append(branch.branches, newBranch)}//Branch class  method getLeafletsfunc (branch *Branch) getLeaflets() []Leaflet {return branch.leafs}// main methodfunc main() {var branch = &Branch{name: "branch 1"}var leaf1 = Leaflet{name: "leaf 1"}var leaf2 = Leaflet{name: "leaf 2"}var branch2 = Branch{name: "branch 2"}branch.add(leaf1)branch.add(leaf2)branch.addBranch(branch2)branch.perform()}

輸出結(jié)果:

G:\GoLang\examples>go run composite.goBranch: branch 1Leaflet leaf 1Leaflet leaf 2Branch: branch 2
Spring 代碼示例

Spring 框架也可以使用組合模式來實現(xiàn)對象的層次結(jié)構(gòu),它提供了一個注解叫做 @Component,它可以用來標注一個類是一個組件,即一個可被Spring管理的Bean對象。@Component注解有一個屬性叫做value,它可以用來指定組件的名稱。我們可以使用 @Component注解來標注我們的文件類,然后在配置文件或注解中聲明這些組件,Spring 就會自動創(chuàng)建和管理這些組件對象。

假設(shè)我們有一個文件系統(tǒng),其中有兩種類型的文件:文本文件和文件夾。文本文件是葉子節(jié)點,文件夾是組合節(jié)點,可以包含其他文件。我們想要使用組合模式來實現(xiàn)文件系統(tǒng)的層次結(jié)構(gòu),并且提供一個打印文件路徑的方法。我們可以使用 @Component注解來實現(xiàn),代碼如下:

抽象組件不用改造

public interface File {    // 獲取文件名稱    String getName();    // 添加子文件    void add(File file);    // 刪除子文件    void remove(File file);    // 獲取子文件    List getChildren();    // 打印文件路徑    void printPath();}

葉子節(jié)點添加 @Component("a.txt")注解

@Component("a.txt")public class TextFile implements File {    private String name;    public TextFile() {        this.name = "a.txt";    }    @Override    public String getName() {        return name;    }    @Override    public void add(File file) {        throw new UnsupportedOperationException("Text file cannot add child file");    }    @Override    public void remove(File file) {        throw new UnsupportedOperationException("Text file cannot remove child file");    }    @Override    public List getChildren() {        throw new UnsupportedOperationException("Text file has no child file");    }    @Override    public void printPath() {        System.out.println(name);    }}

組合節(jié)點添加 @Component("root")注解

@Component("root")public class Folder implements File {    private String name;    private List children;    // 通過@Autowired注解自動注入所有類型為File的Bean對象到children集合中    @Autowired    public Folder(List children) {        this.name = "root";        this.children = children;    }    @Override    public String getName() {        return name;    }    @Override    public void add(File file) {        children.add(file);    }    @Override    public void remove(File file) {        children.remove(file);    }    @Override    public List getChildren() {        return children;    }    @Override    public void printPath() {        System.out.println(name);        for (File child : children) {            child.printPath();        }    }}

SpringBoot 測試代碼

@Slf4j@SpringBootTestclass SpringBootTest {    @Autowired    private Folder folder;    @Test    void test() {        folder.printPath();    }}

輸出結(jié)果:

roota.txt
總結(jié)

組合模式是一種常用的結(jié)構(gòu)型設(shè)計模式,它可以將對象組合成樹形結(jié)構(gòu),并且提供了一致的接口來操作單個對象和對象組合,是一種值得學(xué)習(xí)和掌握的設(shè)計模式。

關(guān)注公眾號【waynblog】每周分享技術(shù)干貨、開源項目、實戰(zhàn)經(jīng)驗、高效開發(fā)工具等,您的關(guān)注將是我的更新動力!

標簽:

返回頂部