組合模式【結構型模式】

一、引入組合模式

設計一個大學>學院>專業的結構代碼,可以做到輸出大學、學院、專業的信息。

  • 一個大學裏面有多個學院
  • 一個學院裏面有多個專業

思路

在這裏插入圖片描述

我們很容易就想到這種組合的方式,去設計我們的代碼。完全沒有問題,可以很好的去實現我們的功能。

但是後面如果變動的時候就麻煩了。 假如我們要讓大學直接去使用專業呢?



二、組合模式

組合模式(Composite Pattern) 將對象組合成樹形結構以表示“部分-整體”的層次結構。組合模式使得用戶可以使用一致的方法操作單個對象和組合對象。

在這裏插入圖片描述

組合模式有三個角色:

組合部件(Component):它可以是抽象類、接口、類。它裏面定義了基本的屬性和方法。
合成部件(Composite):還有自己的子節點,比如這裏的大學、學院
葉子(Leaf):在組合中表示子節點對象,比如這裏的專業。

代碼演示

Component

import lombok.Data;
@Data
public abstract class Component {

     protected String name;

     protected void add(Component component){
         throw new UnsupportedOperationException();
     }

     protected void remove(Component component){
         throw new UnsupportedOperationException();
     }

     abstract void print();
}

注:
    1、比如我們上面的大學裏面有學院,那麼它就需要添加一個學院(add())和刪除一個學院(remove())。但是我們的專業(也就是葉子節點),它不需要這個添加和刪除方法,所以我們進行一個默認實現,裏面拋出這個異常表示不支持此方法。
    2、這裏爲什麼不用接口呢?(JDK8之後允許接口有默認實現),因爲接口裏面不允許定義非常量的變量。


University

import java.util.ArrayList;
import java.util.List;

public class University extends Component {

    private List<Component> lists = new ArrayList<>();

    public University(String name){
        super();
        setName(name);
    }

    @Override
    public void add(Component component) {
        lists.add(component);
    }

    @Override
    public void remove(Component component) {
        lists.remove(component);
    }

    @Override
    public void print() {
        System.out.println("----------"+getName()+"----------");
        for (Component c : lists){
            c.print();
        }
    }
}

College

import java.util.ArrayList;
import java.util.List;

public class College extends Component {

    private List<Component> lists = new ArrayList<>();

    public College(String name){
        super();
        setName(name);
    }

    @Override
    public void add(Component component) {
        lists.add(component);
    }

    @Override
    public void remove(Component component) {
        lists.remove(component);
    }

    @Override
    public void print() {
        System.out.println("----------"+getName()+"----------");
        for (Component c : lists){
            c.print();
        }
    }
}


Major

public class Major extends Component {

    public Major(String name){
        super();
        setName(name);
    }
    
    @Override
    void print() {
        System.out.println(getName());
    }
}

測試

public class Main {
    public static void main(String[] args) {
        // 創建學校
        University university = new University("沙雕大學");

        // 創建學院
        College college_1 = new College("計算機與科學學院");
        College college_2 = new College("人文藝術學院");

        // 大學與學院關聯
        university.add(college_1);
        university.add(college_2);

        // 創建專業
        Major major_1 = new Major("軟件工程");
        Major major_2 = new Major("網絡工程");
        Major major_3 = new Major("音樂與舞蹈");
        Major major_4 = new Major("表演與藝術");

        // 學院與專業關聯
        college_1.add(major_1);
        college_1.add(major_2);
        college_2.add(major_3);
        college_2.add(major_4);

        // 測試
        // 打印大學
        university.print();
        // ----------沙雕大學----------
        // ----------計算機與科學學院----------
        // 軟件工程
        // 網絡工程
        // ----------人文藝術學院----------
        // 音樂與舞蹈
        // 表演與藝術

        // 打印學院
        college_1.print();
        // ----------計算機與科學學院----------
        // 軟件工程
        // 網絡工程

        // 打印專業
        major_1.print();
        // 軟件工程
    }
}

總結

  • 客戶端只需要面對對象即可,不需要考慮整體部分和葉子節點的問題。
  • 具有較強的擴展性。當我們需要更改組合對象時,我們只需要調整內部的層次關係即可。
  • 需要遍歷組織機構,或者處理的對象具有樹形結構時,非常適合使用組合模式。
  • 如果節點和葉子有很多差異的話,比如很多屬性、或方法不一樣,就不適合使用組合模式了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章