欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java設(shè)計模式之組合模式

 更新時間:2022年10月11日 09:07:47   作者:tianClassmate  
這篇文章介紹了Java設(shè)計模式之組合模式,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下

本文通過老王和小王探討書房、書架、各類書的管理問題,引出結(jié)構(gòu)型設(shè)計模式家族中的一個重要成員——組合模式,本文會給予兩種組合模式的典型代碼實現(xiàn),為了加深理解會在第三部分應(yīng)用中介紹組合模式在源碼中的實際運用,最后總結(jié)該設(shè)計模式學(xué)習(xí)后的一些思考。

讀者可以拉取完整代碼到本地進行學(xué)習(xí),實現(xiàn)代碼均測試通過后上傳到碼云,本地源碼下載

一、引出問題

上篇文章中老王給小王買車以后,小王對老王感激涕零,看著老王凌亂的書房,小王提出要幫助老王整理整理他的書架。

小王開始了他的分析。老王平時博覽群書,中文、英文、梵文...每個語種占滿了書架,而每個語種中又分經(jīng)濟學(xué)、計算機學(xué)、社會學(xué)等等類目。這是典型的分層次結(jié)構(gòu),將語種比作是圖書的子類,類目是語種的子類結(jié)構(gòu)劃分。

將圖書、語種、類目都看做是組織結(jié)構(gòu),他們之間沒有繼承關(guān)系,而是一個樹形結(jié)構(gòu),可以更好的實現(xiàn)管理操作。

二、概念與使用

實際上,小王提出來的設(shè)計思路正是結(jié)構(gòu)型設(shè)計模式中的組合模式,我們首先看一下組合模式的相關(guān)概念,組合模式(Composite Pattern),又叫部分整體模式,它創(chuàng)建了對象組的樹形結(jié)構(gòu),將對象組合成樹狀結(jié)構(gòu)以表示“整體-部分”的層次關(guān)系。組合模式依據(jù)樹形結(jié)構(gòu)來組合對象,用來表示部分以及整體層次。

組合模式使得用戶對單個對象和組合對象的訪問具有一致性,即:組合能讓客戶以一致的方式處理個別對象以及組合對象。

用大白話解釋也就是,在實際應(yīng)用中將所有圖書依照樹形模式進行組合,老王尋找書籍時,無論是訪問某一類書還是某一個語種的書,使用同樣的姿勢即可,保證了訪問的一致性。

在該模式中應(yīng)該是有三個角色:

1、Root :這是組合中對象聲明接口,在適當(dāng)情況下,實現(xiàn)所有類共有的接口默認行為,用于訪問和管理Root 子部件, Root 可以是抽象類或者接口。

2、Branches:非葉子節(jié)點用于存儲子部件,在Root接口中實現(xiàn)了 子部件的相關(guān)操作。

2、Leaf : 在組合中表示葉子節(jié)點,葉子節(jié)點沒有子節(jié)點。

小王分析的頭頭是道,老王提出來了他的疑問。

當(dāng)我按語種查找還是按類目查找是使用的方法有時候是不一樣的,如果你把所有方法都定義在Root中,在語種或者類目中實現(xiàn)中是無意義的,而且這違背了接口隔離原則。

小王覺得說的對也不對,如果我改成不在Root中定義,那么我在客戶端調(diào)用的時候就需要判斷是枝還是葉了,增加了繁雜的邏輯判斷,而且相比另外一種變得不透明了,依賴倒置原則也沒有遵守。

兩種方式似乎都有缺陷,小王陷入了糾結(jié)不知道該如何取舍,老王提出了他的一些見解,沒有任何一個設(shè)計模式是完全沒有缺點的,兩種都有各自的好處,在實際的運用中根據(jù)條件進行取舍,而正確選擇的前提就是要對所有的設(shè)計模式充分的把握。

上面兩種就對應(yīng)組合模式中的兩個大分類、①透明組合模式、安全組合模式。

①透明組合模式把所有的公共方法都定義在Root中,這樣做的好處就是客戶端無需分辨是葉子節(jié)點(Leaf)和樹枝節(jié)點(Branches),他們具備完全一致的接口;缺點是葉子節(jié)點(Leaf)會繼承得到一些它所不需要(管理子類操作的方法)的方法,這與設(shè)計模式接口隔離原則相違背。

②安全組合模式的好處是接口定義職責(zé)清晰,符合設(shè)計模式單一職責(zé)原則和接口隔離原則;缺點是客戶需要區(qū)分樹枝節(jié)點(Branches)和葉子節(jié)點(Leaf),這樣才能正確處理各個層次的操作,客戶端依賴抽象(Root),違背了依賴倒置原則。

我們把兩種的方式實現(xiàn),讀者對比他們之間的區(qū)別。

安全模式

Root(根節(jié)點):

/**
 * @author tcy
 * @Date 08-08-2022
 */
public abstract class RootBook {
    protected String name;

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

    public abstract String operation();

}

Branches(樹枝節(jié)點)

/**
 * @author tcy
 * @Date 08-08-2022
 */
public class BranchesLanguages extends RootBook {

    private List<RootBook> roots;

    public BranchesLanguages(String name) {
        super(name);
        this.roots = new ArrayList<RootBook>();
    }


    public String operation() {
        StringBuilder builder = new StringBuilder(this.name);
        for (RootBook component : this.roots) {
            builder.append("\n");
            builder.append(component.operation());
        }
        return builder.toString();

    }
    public boolean addChild(RootBook component) {
        return this.roots.add(component);
    }


    public boolean removeChild(RootBook component) {
        return this.roots.remove(component);
    }


    public RootBook getChild(int index) {
        return this.roots.get(index);
    }

}

Leaf(葉子節(jié)點)

/**
 * @author tcy
 * @Date 08-08-2022
 */
public class LeafClassify extends RootBook {

    public LeafClassify(String name) {
        super(name);
    }

    @Override
    public String operation() {
        return this.name;
    }
}

客戶端:

/**
 * @author tcy
 * @Date 08-08-2022
 */
public class Client {

    public static void main(String[] args) {
        System.out.println("安全組合模式...");
        // 來一個根節(jié)點
        BranchesLanguages BranchesRoot = new BranchesLanguages("root/書");
        // 來一個樹枝節(jié)點
        BranchesLanguages branchA = new BranchesLanguages("------branchA/英語");
        BranchesLanguages branchB = new BranchesLanguages("------branchB/中文");
        // 來一個葉子節(jié)點
        RootBook leafA = new LeafClassify("------leafA/經(jīng)濟學(xué)");
        RootBook leafB = new LeafClassify("------leafB/計算機學(xué)");
        RootBook leafC = new LeafClassify("------leafC/法學(xué)");

        BranchesRoot.addChild(branchA);
        BranchesRoot.addChild(leafC);
        branchA.addChild(leafA);
        branchA.addChild(branchB);
        branchB.addChild(leafB);

        String result = BranchesRoot.operation();
        System.out.println(result);


    }
}

透明模式

Root(根節(jié)點):

/**
 * @author tcy
 * @Date 08-08-2022
 */
public abstract class RootBook {
    protected String name;

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

    public abstract String operation();

    public boolean addChild(RootBook component) {
        throw new UnsupportedOperationException("addChild not supported!");
    }

    public boolean removeChild(RootBook component) {
        throw new UnsupportedOperationException("removeChild not supported!");
    }

    public RootBook getChild(int index) {
        throw new UnsupportedOperationException("getChild not supported!");
    }

}

Branches(樹枝節(jié)點)

/**
 * @author tcy
 * @Date 08-08-2022
 */
public class BranchesLanguages extends RootBook {

    private List<RootBook> roots;

    public BranchesLanguages(String name) {
        super(name);
        this.roots = new ArrayList<RootBook>();
    }


    public String operation() {
        StringBuilder builder = new StringBuilder(this.name);
        for (RootBook component : this.roots) {
            builder.append("\n");
            builder.append(component.operation());
        }
        return builder.toString();

    }

    @Override
    public boolean addChild(RootBook component) {
        return this.roots.add(component);
    }


    @Override
    public boolean removeChild(RootBook component) {
        return this.roots.remove(component);
    }


    @Override
    public RootBook getChild(int index) {
        return this.roots.get(index);
    }

}

Leaf(葉子節(jié)點)

/**
 * @author tcy
 * @Date 08-08-2022
 */
public class LeafClassify extends RootBook {

    public LeafClassify(String name) {
        super(name);
    }

    @Override
    public String operation() {
        return this.name;
    }
}

客戶端:

/**
 * @author tcy
 * @Date 08-08-2022
 */
public class Client {

    public static void main(String[] args) {

        System.out.println("透明組合模式...");
        // 來一個根節(jié)點
        RootBook BranchesRoot = new BranchesLanguages("root/書");
        // 來一個樹枝節(jié)點
        RootBook branchA = new BranchesLanguages("------branchA/英語");
        RootBook branchB = new BranchesLanguages("------branchB/漢語");
        // 來一個葉子節(jié)點
        RootBook leafA = new LeafClassify("------leafA/計算機學(xué)");
        RootBook leafB = new LeafClassify("------leafB/法學(xué)");
        RootBook leafC = new LeafClassify("------leafC/社會學(xué)");

        BranchesRoot.addChild(branchA);
        BranchesRoot.addChild(leafC);
        branchA.addChild(leafA);
        branchA.addChild(branchB);
        branchB.addChild(leafB);

        String result = BranchesRoot.operation();
        System.out.println(result);


    }
}

使用組合模式的兩種實現(xiàn)方法,這樣就對老王的書架改造工程就完成了,對憑空捏造出來的需求有些讀者看完想必還是云里霧里。我們結(jié)合JDK的源碼和一些開發(fā)常用框架,再次深入源碼對組合模式的使用。

三、應(yīng)用

通過查詢資料可知,組合模式在Jdk中的應(yīng)用主要是集合類HashMap和Mybtis中的SqlNode。

我們分別看其實現(xiàn)。

1、jdk中HashMap的運用

在HashMap中有一個父類AbstractMap和一個子類Node。如下圖

我們看下源代碼:

 public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {
    ...
     public void putAll(Map<? extends K, ? extends V> m) {
        putMapEntries(m, true);
    }
    ...
    final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
        int s = m.size();
        if (s > 0) {
            if (table == null) { // pre-size
                float ft = ((float)s / loadFactor) + 1.0F;
                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                         (int)ft : MAXIMUM_CAPACITY);
                if (t > threshold)
                    threshold = tableSizeFor(t);
            }
            else if (s > threshold)
                resize();
            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
                K key = e.getKey();
                V value = e.getValue();
                putVal(hash(key), key, value, false, evict);
            }
        }
    }
    ...
}

putAll()方法傳入的是Map對象,Map就是一個抽象構(gòu)件(同時這個構(gòu)件中只支持健值對的存儲格式),而HashMap是一個中間構(gòu)件,HashMap中的Node節(jié)點就是葉子節(jié)點。

Node是HashMap中的一個內(nèi)部類,HashMap的存儲節(jié)點指的正是Node,讀者可以重點看這個類的實現(xiàn)。

在這個實例中,HashMap就是樹枝節(jié)點,Node就是葉節(jié)點,Map就是根節(jié)點。

2、Mybtis中的SqlNode

SqlNode是一個接口,主要功能就是構(gòu)造SQL語句。

public interface SqlNode {
  boolean apply(DynamicContext context);
}

SqlNode有一大堆的實現(xiàn)類,我們看其中的MixedSqlNode。

  public class MixedSqlNode implements SqlNode {
  private final List<SqlNode> contents;

  public MixedSqlNode(List<SqlNode> contents) {
    this.contents = contents;
  }

  @Override
  public boolean apply(DynamicContext context) {
    contents.forEach(node -> node.apply(context));
    return true;
  }
}

SqlNode就充當(dāng)組合模式中的Root,而他的眾多子類作用就在于拼接各種類型的SQL,在組合模式的角色中相當(dāng)于樹枝節(jié)點。其中在TrimSqlNode 中有一個子類WhereSqlNode就充當(dāng)組合模式中的樹葉節(jié)點。

這兩個都屬于組合模式中的典型例子,讀者體會下使用這種模式的好處,和如果不使用組合模式應(yīng)該怎樣實現(xiàn)。

通過這兩個例子我們應(yīng)該可以看到,設(shè)計模式的使用中并不是完全遵循各自的角色,更多的是設(shè)計模式中的一些變種,讀者不深入源碼并不能了解到該模式的實現(xiàn)細節(jié)。讀者需要做的就是盡可能的熟悉設(shè)計模式,在自己開發(fā)過程中可以“擇優(yōu)錄取”。

四、總結(jié)

到這里組合模式也就介紹完了,這種模式的優(yōu)缺點都非常的明顯,優(yōu)點就在于清楚的定義分層次的結(jié)構(gòu),在調(diào)用時忽略他們之間的差異,方便對整個層次進行控制,但是組合模式會違反依賴倒置原則。

理解是一回事,在實際應(yīng)用中能正確的使用它就是另外一回事了。

讀者要對每種設(shè)計模式都能做到心中有數(shù),當(dāng)我們在實際編程中,在潛意識里有各個設(shè)計模式的大體輪廓,參考代入進各種設(shè)計模式中,對于簡化開發(fā)和易于維護性有沒有好的幫助,選擇一個最優(yōu)的設(shè)計模式。

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請查看下面相關(guān)鏈接

相關(guān)文章

  • 詳解SpringBoot應(yīng)用服務(wù)啟動與安全終止

    詳解SpringBoot應(yīng)用服務(wù)啟動與安全終止

    這篇文章主要介紹了SpringBoot應(yīng)用服務(wù)啟動與安全終止,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • SpringBoot升級指定jackson版本的問題

    SpringBoot升級指定jackson版本的問題

    這篇文章主要介紹了SpringBoot升級指定jackson版本,本文給大家分享了漏洞通告及修改Springboot中jackson版本的問題,需要的朋友可以參考下
    2022-08-08
  • Java面試之限流的實現(xiàn)方式小結(jié)

    Java面試之限流的實現(xiàn)方式小結(jié)

    限流是指在各種應(yīng)用場景中,通過技術(shù)和策略手段對數(shù)據(jù)流量、請求頻率或資源消耗進行有計劃的限制,本文為大家整理了常見的限流的實現(xiàn)方式,有需要的可以參考下
    2024-02-02
  • 詳解如何獨立使用ribbon實現(xiàn)業(yè)務(wù)客戶端負載均衡

    詳解如何獨立使用ribbon實現(xiàn)業(yè)務(wù)客戶端負載均衡

    這篇文章主要為大家介紹了詳解如何獨立使用ribbon實現(xiàn)業(yè)務(wù)客戶端負載均衡,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • zookeeper+Springboot實現(xiàn)服務(wù)器動態(tài)上下線監(jiān)聽教程詳解

    zookeeper+Springboot實現(xiàn)服務(wù)器動態(tài)上下線監(jiān)聽教程詳解

    這篇文章主要介紹了zookeeper+Springboot實現(xiàn)服務(wù)器動態(tài)上下線監(jiān)聽,主要介紹了什么是服務(wù)器動態(tài)上下線監(jiān)聽及為什么要實現(xiàn)對服務(wù)器上下線的監(jiān)聽,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2022-06-06
  • Java 實現(xiàn)隨機驗證碼功能簡單實例

    Java 實現(xiàn)隨機驗證碼功能簡單實例

    這篇文章主要介紹了Java 實現(xiàn)隨機驗證碼功能簡單實例的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • Java中執(zhí)行docker命令的實現(xiàn)示例

    Java中執(zhí)行docker命令的實現(xiàn)示例

    本文主要介紹了Java中執(zhí)行docker命令的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • HttpClient的DnsResolver自定義DNS解析另一種選擇深入研究

    HttpClient的DnsResolver自定義DNS解析另一種選擇深入研究

    這篇文章主要為大家介紹了HttpClient的DnsResolver自定義DNS解析另一種選擇深入研究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • Java結(jié)合百度云存儲BCS代碼分享

    Java結(jié)合百度云存儲BCS代碼分享

    最近云是一個很熱門的新概念,仿佛任何東西只要跟云相關(guān)聯(lián),就立馬高大上起來,額,我們也追隨潮流吧,項目中也結(jié)合一下云!!
    2014-10-10
  • java數(shù)組及arrays類對數(shù)組的操作實例

    java數(shù)組及arrays類對數(shù)組的操作實例

    下面小編就為大家?guī)硪黄猨ava數(shù)組及arrays類對數(shù)組的操作實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10

最新評論