自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

【結構型】樹形結構的應用王者,組合模式

開發(fā) 前端
組合模式(Composite Pattern)是一種結構型設計模式,適用于將對象組合成樹形結構來表示“部分-整體”的層次關系。它允許用戶像使用單個對象一樣操作對象組合,簡化了復雜結構的處理。

在日常開發(fā)中,我們往往忽視了設計模式的重要性。這可能是因為項目時間緊迫,或者對設計模式理解不深。其實,很多時候我們可能在不經意間已經使用了某些模式。

重要的是要有意識地學習和應用,讓代碼更加優(yōu)雅和高效。也許是時候重新審視我們的編程實踐,將設計模式融入其中了。

今天由淺入深,重學【組合模式】,讓我們一起“重學設計模式”。

一、組合模式

1.組合模式是什么?

組合模式(Composite Pattern)是一種結構型設計模式,它允許你將對象組合成樹形結構來表示“部分-整體”的層次結構。組合模式使得用戶可以像使用單個對象一樣使用對象組合,簡化了復雜結構的處理。

2.組合模式的主要參與者:

  1. Component(抽象組件):定義了對象的接口,所有組合對象和葉子節(jié)點都應實現(xiàn)它。
  2. Leaf(葉子節(jié)點):表示沒有子節(jié)點的對象,即樹的末端。
  3. Composite(組合對象):表示擁有子節(jié)點的對象。它不僅實現(xiàn)了 Component 接口,還能夠存儲并管理其子節(jié)點。

二、優(yōu)化案例:文件系統(tǒng)

文件系統(tǒng)是組合模式的經典案例。文件系統(tǒng)中的文件夾可以包含文件或其他文件夾。無論是文件還是文件夾,它們都應該有一些共同的行為,例如顯示名稱或計算大小。

1.不使用組合模式

如果不采用組合模式,代碼將需要分別處理葉子節(jié)點(如文件)和組合對象(如文件夾),這會導致代碼復雜性增加。沒有統(tǒng)一的接口意味著文件和文件夾需要不同的處理邏輯,導致代碼的重復和不易擴展。

每次添加新的文件類型或子文件夾時,都需要修改已有代碼,增加文件和文件夾的處理邏輯,代碼會變得難以維護和擴展。

  • 冗余代碼:Folder 類中有兩個集合,一個存儲文件,另一個存儲子文件夾。由于沒有通用接口,必須為文件和文件夾分別編寫邏輯。
  • 缺乏一致性:要操作文件和文件夾時,必須分別對待。例如,showDetails() 方法中,文件和文件夾需要分開處理,無法將它們統(tǒng)一成一個對象。
  • 擴展性差:如果將來想要添加新的類型,比如符號鏈接、壓縮文件等,必須分別為它們定義類,并在每個相關的邏輯中添加處理它們的代碼。
public class File {

    private String name;
    private int size;

    public File(String name, int size) {
        this.name = name;
        this.size = size;
    }

    public void showDetails() {
        System.out.println("File: " + name + " (Size: " + size + " KB)");
    }
}

public class Folder {
    private String name;
    private List<File> files = new ArrayList<>();
    private List<Folder> subFolders = new ArrayList<>();

    public Folder(String name) {
        this.name = name;
    }

    public void addFile(File file) {
        files.add(file);
    }

    public void addFolder(Folder folder) {
        subFolders.add(folder);
    }

    public void showDetails() {
        System.out.println("Folder: " + name);

        // 顯示文件夾中的文件
        for (File file : files) {
            file.showDetails();
        }

        // 遞歸顯示子文件夾中的內容
        for (Folder folder : subFolders) {
            folder.showDetails();
        }
    }
}

public class Test {

    public static void main(String[] args) {
        File file1 = new File("Document.txt", 50);
        File file2 = new File("Photo.jpg", 200);

        Folder folder = new Folder("MyFolder");
        folder.addFile(file1);
        folder.addFile(file2);


        File file3 = new File("test0.txt", 50);
        File file4 = new File("test1.jpg", 200);

        Folder folderRoot = new Folder("MyFolderRoot");
        folderRoot.addFile(file3);
        folderRoot.addFile(file4);

        folderRoot.addFolder(folder);

        folderRoot.showDetails();
    }
}

2.通過組合模式優(yōu)化上面代碼

在電子商務網站的產品目錄中,可以通過組合模式管理產品和產品類別。每個產品(葉子節(jié)點)具有價格和描述,產品類別(組合對象)可以包含其他類別或產品。通過使用組合模式,可以簡化查詢價格、庫存和類別層次的操作。

優(yōu)化點:

  • 簡化層次結構:在系統(tǒng)中,產品與類別都遵循相同的接口,可以統(tǒng)一處理產品和類別。
  • 靈活性:可以動態(tài)地增加或移除產品和類別,提高系統(tǒng)的可擴展性和維護性。

這個模式特別適合應用于具有遞歸或樹形結構的場景。

文件和文件夾可以看作統(tǒng)一的組件,處理邏輯一致,新增類型時只需實現(xiàn)抽象接口,原有代碼不需要修改。

/**
 * 抽象組件
 */
public abstract class FileSystemComponent {

    public abstract void showDetails();
}

/**
 * 葉子節(jié)點:文件
 */
public class File extends FileSystemComponent {

    private String name;
    private int size;

    public File(String name, int size) {
        this.name = name;
        this.size = size;
    }

    @Override
    public void showDetails() {
        System.out.println("File: " + name + " (Size: " + size + " KB)");
    }
}

/**
 * 組合對象:文件夾
 */
public class Folder extends FileSystemComponent {

    private String name;
    private List<FileSystemComponent> components = new ArrayList<>();

    public Folder(String name) {
        this.name = name;
    }

    public void addComponent(FileSystemComponent component) {
        components.add(component);
    }

    @Override
    public void showDetails() {
        System.out.println("Folder: " + name);
        for (FileSystemComponent component : components) {
            component.showDetails();
        }
    }
}

public class CombinationClient {
    public static void main(String[] args) {
        FileSystemComponent file1 = new File("Document.txt", 50);
        FileSystemComponent file2 = new File("Photo.jpg", 200);

        Folder folder = new Folder("MyFolder");
        folder.addComponent(file1);
        folder.addComponent(file2);

        File file3 = new File("test0.txt", 50);
        File file4 = new File("test1.jpg", 200);

        Folder folderRoot = new Folder("MyFolderRoot");
        folderRoot.addComponent(file3);
        folderRoot.addComponent(file4);

        folderRoot.addComponent(folder);

        folderRoot.showDetails();
    }
}

三、使用組合模式有哪些優(yōu)勢

1.統(tǒng)一接口,簡化客戶端代碼

組合模式為對象和對象組合提供了統(tǒng)一的接口,客戶端可以一致地操作單個對象和組合對象,而不必區(qū)分它們是葉子還是組合。這種一致性減少了處理不同類型對象的復雜度,簡化了代碼。

2.遞歸結構處理方便

組合模式特別適合處理樹形或遞歸結構,如文件系統(tǒng)、組織結構等。通過遞歸調用,可以輕松遍歷整個結構(無論是文件還是文件夾),不必寫不同的處理邏輯。

3.易擴展

新增葉子節(jié)點或組合對象時,只需實現(xiàn)相同的接口,不需要修改已有的代碼。組合模式具有開放-封閉原則的優(yōu)勢,使系統(tǒng)更加靈活、易于擴展。

4.簡化客戶端操作

客戶端不再需要關心對象的具體類型(葉子或組合),只需處理抽象組件。這使得代碼更加簡潔,也減少了錯誤處理的復雜性。

5.動態(tài)組合靈活

通過組合模式,可以動態(tài)地組合對象,而無需預先定義復雜的類結構。這為復雜對象提供了靈活的處理方式,使得系統(tǒng)結構更具彈性。

四、適用場景

  • 樹形結構(層次結構):組合模式非常適用于需要表示“部分-整體”關系的場景,尤其是樹形結構。例如,文件系統(tǒng)、組織結構圖、產品目錄樹、菜單系統(tǒng)等。
  • 文件系統(tǒng):文件和文件夾之間的層次關系可以通過組合模式來輕松管理。無論是單個文件,還是包含子文件夾的文件夾,都可以通過相同的方式處理。
  • 組織結構圖:公司中員工和部門之間存在層次結構,員工可以屬于某個部門,部門可以屬于其他部門,通過組合模式,可以方便地管理和展示這種結構。
  • GUI控件(圖形用戶界面):GUI 組件經常包含其他組件,如按鈕、窗口、面板等。組合模式可以用來管理這些圖形控件,讓它們統(tǒng)一處理。例如,一個窗口可能包含面板,面板中包含按鈕和文本框,這些控件都可以通過相同的接口進行管理和渲染。
  • 菜單系統(tǒng):菜單項可以包含子菜單,也可以是普通的菜單項。組合模式可以用于菜單系統(tǒng)的設計,使得菜單項和子菜單都實現(xiàn)相同的接口,從而簡化菜單的顯示和操作。
  • 產品目錄和分類管理:電子商務網站中,產品可以屬于某個類別,類別之間也有層次結構。組合模式可以用于管理產品和類別,通過統(tǒng)一接口可以輕松查詢、操作或統(tǒng)計不同類別下的產品信息。
  • 圖形繪制系統(tǒng):在圖形繪制系統(tǒng)中,復雜的圖形可能是由多個簡單圖形組成的。組合模式允許將簡單圖形和復雜圖形統(tǒng)一起來處理,方便實現(xiàn)圖形的遞歸繪制和操作。
  • 權限系統(tǒng):在權限管理中,角色和權限之間可能存在層次關系,一個角色可以擁有多個權限,權限可以包含子權限。組合模式可以用于簡化權限系統(tǒng)的設計,使得權限的分配和管理更加靈活。
  • 編譯器中的抽象語法樹(AST):編譯器在解析源代碼時,會生成抽象語法樹(AST),其中每個節(jié)點可以是語法結構的一個元素(如表達式、語句等)。通過組合模式,編譯器可以對這些節(jié)點進行統(tǒng)一處理,而不需要關心它們的具體類型。

五、組合模式的劣勢

雖然組合模式有很多優(yōu)勢,但它也有一些潛在的劣勢:

  • 過度抽象:為了實現(xiàn)通用接口,可能導致系統(tǒng)設計過于抽象和復雜,尤其是在層次結構非常深的情況下,增加了理解和維護的難度。
  • 性能問題:由于組合模式需要遞歸處理對象結構,在大規(guī)模、深層次的樹形結構中,遞歸操作可能帶來性能問題。
  • 類型安全問題:組合模式統(tǒng)一了葉子節(jié)點和組合對象的接口,有時可能難以強制類型檢查。例如,某些操作只對葉子節(jié)點有效,調用這些操作時可能需要額外的類型判斷。

六、在jdk源碼中,哪些地方應用了組合模式,代碼舉例說明一下

在JDK源碼中,組合模式被廣泛應用于處理樹形或層次結構的數據結構和設計,最典型的例子之一是 java.awt 包中的 Component 類,以及集合框架中的 java.util 包。

以下是兩個常見的應用場景:

1.AWT(Abstract Window Toolkit)中的組件樹

在 java.awt 包中,Component 類和 Container 類使用了組合模式。Container 代表可以包含子組件的對象,而 Component 是一個抽象組件,代表所有的 GUI 元素。Container 既可以是單個組件(葉子),也可以是組合組件(容器),從而形成了一個樹形的 GUI 組件層次結構。

(1)代碼分析:

  1. Component 類是所有 GUI 元素的基類。
  2. Container 類是 Component 的子類,它可以包含多個子組件。

(2)JDK 源碼中的示例(簡化):

// java.awt.Component
public abstract class Component {
    // 省略大量方法
    public void paint(Graphics g) {
        // 繪制組件的代碼
    }
}

// java.awt.Container
public class Container extends Component {
    // 存儲子組件
    private List<Component> componentList = new ArrayList<>();

    public void add(Component comp) {
        componentList.add(comp);
    }

    public void remove(Component comp) {
        componentList.remove(comp);
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        // 遞歸調用子組件的 paint 方法
        for (Component comp : componentList) {
            comp.paint(g);
        }
    }
}

(3)組合模式分析:

  1. Component 是一個抽象類,定義了所有組件的通用接口。
  2. Container 是一個組合對象,包含其他組件,并可以遞歸地管理和繪制這些組件。
  3. 在使用時,GUI 系統(tǒng)可以統(tǒng)一處理 Component 對象,不論它是葉子組件(如按鈕、文本框),還是組合組件(如面板、窗口)。

2.集合框架中的 java.util 包

在 Java 集合框架中,List、Set、Map 等接口也使用了組合模式。集合類中既有可以直接存儲元素的類(如 ArrayList、HashSet),也有可以組合其他集合的類(如 Collections.unmodifiableList、Collections.synchronizedList 等)。

(1)代碼分析:

  1. List 接口是所有列表的通用接口。
  2. ArrayList 實現(xiàn)了 List 接口,代表葉子節(jié)點,可以直接存儲元素。
  3. Collections.unmodifiableList 通過組合模式,將一個已有的列表封裝起來,實現(xiàn)不可修改的列表。

(2)JDK 源碼中的示例:

// java.util.List (接口)
public interface List<E> extends Collection<E> {
    // 定義列表的通用方法
    boolean add(E e);
    E get(int index);
    // 省略其他方法
}

// java.util.ArrayList (葉子節(jié)點)
public class ArrayList<E> extends AbstractList<E> implements List<E> {
    private Object[] elementData;
    private int size;
    
    public ArrayList() {
        elementData = new Object[10];
    }

    @Override
    public boolean add(E e) {
        // 添加元素的邏輯
        elementData[size++] = e;
        return true;
    }

    @Override
    public E get(int index) {
        return (E) elementData[index];
    }
    // 省略其他方法
}

// java.util.Collections.unmodifiableList (組合對象)
public static <T> List<T> unmodifiableList(List<? extends T> list) {
    return new UnmodifiableList<>(list);
}

// 內部類,包裝一個已有的 List
private static class UnmodifiableList<E> extends AbstractList<E> {
    private final List<? extends E> list;

    UnmodifiableList(List<? extends E> list) {
        this.list = Objects.requireNonNull(list);
    }

    @Override
    public E get(int index) {
        return list.get(index);
    }

    @Override
    public boolean add(E e) {
        throw new UnsupportedOperationException();
    }
}

(3)組合模式分析:

  1. List 接口是抽象組件,定義了所有列表操作的通用方法。
  2. ArrayList 是具體的葉子節(jié)點,可以直接存儲和操作元素。
  3. UnmodifiableList 是一個組合對象,它通過包裝另一個 List 實現(xiàn)不可修改的列表,并且與其他 List 一樣實現(xiàn)了 List 接口。
  4. List 和 ArrayList 之間的關系符合組合模式:ArrayList 作為葉子節(jié)點實現(xiàn)了通用的 List 接口,而 UnmodifiableList 通過組合其他列表來擴展功能,形成了一個樹形的結構。

3.小總結

組合模式在 JDK 中的應用主要體現(xiàn)在處理層次結構、遞歸結構的場景。AWT 中的 Component 和 Container 類,集合框架中的 List 接口及其實現(xiàn),都采用了組合模式。通過這種設計,Java 提供了靈活而統(tǒng)一的接口,簡化了對復雜對象結構的處理,同時保持了系統(tǒng)的可擴展性。

七、總結

組合模式(Composite Pattern)是一種結構型設計模式,適用于將對象組合成樹形結構來表示“部分-整體”的層次關系。它允許用戶像使用單個對象一樣操作對象組合,簡化了復雜結構的處理。組合模式的主要參與者包括抽象組件(Component),葉子節(jié)點(Leaf),和組合對象(Composite)。每個組件通過統(tǒng)一接口,支持遞歸處理子節(jié)點,使得系統(tǒng)更加靈活、易擴展。

以文件系統(tǒng)為例,文件夾可以包含文件或其他文件夾。在不使用組合模式時,文件和文件夾必須分別處理,導致代碼復雜性增加且擴展性差。通過組合模式,可以使用統(tǒng)一的接口管理文件和文件夾,簡化層次結構并增強系統(tǒng)的擴展性和靈活性。

組合模式在JDK源碼中有廣泛應用,如 java.awt 中的組件樹(Component 和 Container 類),以及集合框架中的 List、ArrayList 和 Collections.unmodifiableList。這些類通過組合模式處理遞歸結構和對象組合,使得操作統(tǒng)一、靈活。

責任編輯:姜華 來源: 哪吒編程
相關推薦

2020-06-08 08:04:49

設計模式結構型接口

2009-09-27 13:57:19

Hibernate樹形

2013-12-25 09:53:22

Ember.js應用

2010-05-24 19:17:12

SNMP對象

2017-02-08 14:16:17

C代碼終端

2024-04-12 12:10:18

Python設計模式開發(fā)

2021-09-16 06:44:05

組合模式設計

2018-05-22 14:30:42

云計算虛擬化模式

2012-04-12 09:38:21

JavaScript

2010-07-06 10:19:15

SQL Server層

2021-11-10 07:47:49

組合模式場景

2010-04-08 09:27:04

PHP設計模式結構模式

2012-07-09 09:31:53

silverlight

2017-05-16 21:31:03

結構化數據新模式

2009-12-16 14:40:14

Ruby控制結構

2010-05-07 15:32:13

Oracle物理結構

2013-09-02 15:53:16

Windows

2023-10-27 10:17:46

設計模式訪問者元素

2009-08-13 14:24:44

C#結構體構造函數

2023-12-08 09:15:53

Java單表樹形結構Tree
點贊
收藏

51CTO技術棧公眾號