1. 程式人生 > >java設計模式——組合模式

java設計模式——組合模式

double ble 改進 != 層次 客戶端 stat item uml

一. 定義與類型

定義:將對象組合成樹形結構以表示“部分-整體”的層次結構,組合模式使客戶端對單個對象和組合對象保持一致的方式處理

類型:結構性

假設有一個樹形結構的菜單,而在菜單中還可能有子菜單,子菜單下還可能有子菜單,子菜單下還有文件等等, 這種情況下可以使用組合模式。

技術分享圖片

二. 使用場景

(1) 希望客戶端可以忽略組合對象與單個對象的差異

(2) 處理一個樹形結構

三. 優缺點

優點:

  (1) 清楚的定義層次的復雜對象,表示對象的全部或部分層次

  (2) 讓客戶端忽略了層次的差異,方便對整個層次結構進行控制

  (3) 簡化客戶端代碼

  (4) 符合開閉原則

缺點:

  (1) 限制類型時會較為復雜

  (2) 使設計變得更加抽象

四. 相關設計模式

組合模式和訪問者模式

  可以使用訪問者模式來訪問組合模式的遞歸結構

五. Coding

以課程目錄與課程為例,課程目錄有目錄名稱,課程有名稱與價格,它們不是同一類實體,但是它們可以組合成整體一套課程。

創建一個目錄組件類:

/**
 * @program: designModel
 * @description:
 * @author: YuKai Fan
 * @create: 2019-02-12 11:36
 **/
public abstract class CatalogComponent {
    public void add(CatalogComponent catalogComponent) {
        
throw new UnsupportedOperationException("不支持添加操作"); } public void remove(CatalogComponent catalogComponent) { throw new UnsupportedOperationException("不支持刪除操作"); } public String getName(CatalogComponent catalogComponent) { throw new UnsupportedOperationException("不支持獲取名稱操作"); }
public double getPrice(CatalogComponent catalogComponent) { throw new UnsupportedOperationException("不支持獲取價格操作"); } public void print() { throw new UnsupportedOperationException("不支持打印操作"); } }

創建一個課程類,繼承組件類:

/**
 * @program: designModel
 * @description: 課程類
 * @author: YuKai Fan
 * @create: 2019-02-12 11:39
 **/
public class Course extends CatalogComponent {
    private String name;
    private double price;

    public Course(String name, double price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public String getName(CatalogComponent catalogComponent) {
        return this.name;
    }

    @Override
    public double getPrice(CatalogComponent catalogComponent) {
        return this.price;
    }

    @Override
    public void print() {
        System.out.println("Course Name:" + name + "Price:" + price);
    }
}

在創建一個課程目錄類,也繼承組件類:

/**
 * @program: designModel
 * @description: 課程目錄類
 * @author: YuKai Fan
 * @create: 2019-02-12 11:41
 **/
public class CourseCatalog extends CatalogComponent{
    private List<CatalogComponent> items = new ArrayList<CatalogComponent>();
    private String name;public CourseCatalog(String name) {
        this.name = name;
    }

    @Override
    public void add(CatalogComponent catalogComponent) {
        items.add(catalogComponent);
    }

    @Override
    public void remove(CatalogComponent catalogComponent) {
        items.remove(catalogComponent);
    }

    @Override
    public void print() {
        System.out.println(this.name);
        for (CatalogComponent catalogComponent : items) {
           
                    System.out.print(" ");
                
            }
            catalogComponent.print();
        }
    }
}

應用層:

/**
 * @program: designModel
 * @description:
 * @author: YuKai Fan
 * @create: 2019-02-12 11:47
 **/
public class Test {
    public static void main(String[] args) {
        CatalogComponent linuxCourse = new Course("Linux課程", 11);
        CatalogComponent windowsCourse = new Course("Windows課程", 15);

        CatalogComponent javaCourseCatalog = new CourseCatalog("Java課程");

        CatalogComponent mmallCourse1 = new Course("Java電商一期", 55);
        CatalogComponent mmallCourse2 = new Course("Java電商二期", 66);
        CatalogComponent designPattern = new Course("Java設計模式", 77);

        javaCourseCatalog.add(mmallCourse1);
        javaCourseCatalog.add(mmallCourse2);
        javaCourseCatalog.add(designPattern);

        CatalogComponent mainCourseCatalog = new CourseCatalog("課程主目錄");
        mainCourseCatalog.add(linuxCourse);
        mainCourseCatalog.add(windowsCourse);
        mainCourseCatalog.add(javaCourseCatalog);

        mainCourseCatalog.print();


    }
}

結果:

課程主目錄
 Course Name:Linux課程Price:11.0
 Course Name:Windows課程Price:15.0
 Java課程
 Course Name:Java電商一期Price:55.0
 Course Name:Java電商二期Price:66.0
 Course Name:Java設計模式Price:77.0

Process finished with exit code 0

從上面的結果可以看出,java課程與課程主目錄都屬於目錄,只不過等級不同,所以需要根據等級來動態的判斷。例如一級目錄,二級目錄等等。

這些事組合模式的缺點,限制類型時會比較復雜。所以將上面代碼進行改進。

課程目錄類:

/**
 * @program: designModel
 * @description: 課程目錄類
 * @author: YuKai Fan
 * @create: 2019-02-12 11:41
 **/
public class CourseCatalog extends CatalogComponent{
    private List<CatalogComponent> items = new ArrayList<CatalogComponent>();
    private String name;
    private Integer level;

    public CourseCatalog(String name, Integer level) {
        this.name = name;
        this.level = level;
    }

    @Override
    public void add(CatalogComponent catalogComponent) {
        items.add(catalogComponent);
    }

    @Override
    public void remove(CatalogComponent catalogComponent) {
        items.remove(catalogComponent);
    }

    @Override
    public void print() {
        System.out.println(this.name);
        for (CatalogComponent catalogComponent : items) {
            if (this.level != null) {
                for (int i = 0; i < this.level; i++) {
                    System.out.print(" ");
                }
            }
            catalogComponent.print();
        }
    }
}

應用層:

/**
 * @program: designModel
 * @description:
 * @author: YuKai Fan
 * @create: 2019-02-12 11:47
 **/
public class Test {
    public static void main(String[] args) {
        CatalogComponent linuxCourse = new Course("Linux課程", 11);
        CatalogComponent windowsCourse = new Course("Windows課程", 15);

        CatalogComponent javaCourseCatalog = new CourseCatalog("Java課程",2);

        CatalogComponent mmallCourse1 = new Course("Java電商一期", 55);
        CatalogComponent mmallCourse2 = new Course("Java電商二期", 66);
        CatalogComponent designPattern = new Course("Java設計模式", 77);

        javaCourseCatalog.add(mmallCourse1);
        javaCourseCatalog.add(mmallCourse2);
        javaCourseCatalog.add(designPattern);

        CatalogComponent mainCourseCatalog = new CourseCatalog("課程主目錄",1);
        mainCourseCatalog.add(linuxCourse);
        mainCourseCatalog.add(windowsCourse);
        mainCourseCatalog.add(javaCourseCatalog);

        mainCourseCatalog.print();


    }
}

結果:

技術分享圖片

UML類圖:

技術分享圖片

組合模式將多個對象組合成樹形結構以表示“整體-部分”的結構層次。組合模式對單個對象(葉子對象)和組合對象(容器對象)的使用具有一致性。

六. 源碼分析

(1)jdk

List中的ArrayList中的addAll()方法,以及HashMap中的putAll方法都是通過繼承方式的組合模式體現

(2)mybatis

SqlNode接口,該接口有很多的實現類,都是通過組合模式將多個sqlNode結合到一起(有的是組合關系,有的不是)。

技術分享圖片

java設計模式——組合模式