【源碼分析設計模式 6】Mybatis中的組合模式

一、基本介紹

組合模式,將對象組合成樹形結構以表示“整體-部分”的層次結構,一種對象結構型模式。

由於在軟件開發中存在大量的樹形結構,因此組合模式是一種使用頻率較高的結構型設計模式,Java SE中的AWT和Swing包的設計就基於組合模式。除此以外,在XML解析、組織結構樹處理、文件系統設計等領域,組合模式都得到了廣泛應用。

組合模式的分類:

1、透明組合模式

透明組合模式中,抽象構件角色中聲明瞭所有對於管理成員對象的方法,透明組合模式是組合模式的標準形式。

2、安全組合模式

安全組合模式中,在抽象構件角色中沒有聲明任何用於管理成員對象的方法,而是在容器構件類中聲明並實現這些方法。

二、組合模式的結構

1、Component(抽象構件)

它可以是接口或抽象類,以葉子構件和容器構件對象聲明接口,在該角色中可以包含所有子類共有行爲的聲明和實現。在抽象構件中定義了訪問及管理它的子構件的方法,如增加子構件、刪除子構件、獲取子構件等。

2、Composite(容器構件)

它在組合結構中表示容器節點對象,容器節點包含子節點,其子節點可以是葉子節點,也可以是容器節點,它提供一個集合用於存儲子節點,實現了抽象構件中定義的行爲,包括哪些訪問及管理子構件的方法,在其業務方法中可以遞歸調用其子節點的業務方法。

3、Leaf(葉子構件)

它在組合結構中表示葉子節點對象,葉子節點沒有子節點,它實現了在抽象構件中定義的行爲。對於那些訪問及管理子構件的方法,可以通過異常等方式進行處理。

組合模式的關鍵是定義了一個抽象構件類,它既可以代表葉子,又可以代表容器,而客戶端針對該抽象構件類進行編程,無須知道它到底表示的是葉子還是容器,可以對其進行統一處理。同時容器對象與抽象構件類之間還建立一個聚合關聯關係,在容器對象中既可以包含葉子,也可以包含容器,以此實現遞歸組合,形成一個樹形結構。

三、組合模式優缺點

 

1、優點

(1)組合模式可以清晰的定義分層次的複雜對象,表示對象的全部或部分層次,它讓客戶端忽略了層次的差異,方便對整個層次結構進行控制。

(2)客戶端可以一致地使用一個組合結構或其中單個對象,不必關心處理的是單個對象還是整個組合結構,簡化了客戶端代碼。

(3)在組合模式中增加新的容器構件和葉子構件都很方便,無須對現有類庫進行任何修改,符合“開閉原則”。

(4)組合模式爲樹形結構的面向對象實現提供了一種靈活的解決方案,通過葉子對象和容器對象的遞歸組合,可以形成複雜的樹形結構,但對樹形結構的控制卻非常簡單。

2、缺點

(1)使得設計更加複雜,客戶端需要花更多時間理清類之間的層次關係。

(2)在增加新構件時很難對容器中的構件類型進行限制。

四、組合模式的使用場景

1、在具有整體和部分的層次結構中,希望通過一種方式忽略整體與部分的差異,客戶端可以一致地對待它們。

2、在一個使用面嚮對象語言開發的系統中需要處理一個樹形結構。

3、在一個系統中能夠分離出葉子對象和容器對象,而且它們的類型不固定,需要增加一些新的類型。

五、組合模式實現學校院系展示

1、抽象構件

package designMode.advance.composite;

public abstract class OrganizationComponent {
    private String name; // 名字
    private String des; // 說明

    protected  void add(OrganizationComponent organizationComponent) {
        //默認實現
        throw new UnsupportedOperationException();
    }

    protected  void remove(OrganizationComponent organizationComponent) {
        //默認實現
        throw new UnsupportedOperationException();
    }

    //構造器
    public OrganizationComponent(String name, String des) {
        super();
        this.name = name;
        this.des = des;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDes() {
        return des;
    }

    public void setDes(String des) {
        this.des = des;
    }

    //方法print, 做成抽象的, 子類都需要實現
    protected abstract void print();
}

2、容器構件 --> 學校類

package designMode.advance.composite;

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

public class University extends OrganizationComponent {
    List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>();

    // 構造器
    public University(String name, String des) {
        super(name, des);
    }

    // 重寫add
    @Override
    protected void add(OrganizationComponent organizationComponent) {
        organizationComponents.add(organizationComponent);
    }

    // 重寫remove
    @Override
    protected void remove(OrganizationComponent organizationComponent) {
        organizationComponents.remove(organizationComponent);
    }

    @Override
    public String getName() {
        return super.getName();
    }

    @Override
    public String getDes() {
        return super.getDes();
    }

    // print方法,就是輸出University 包含的學院
    @Override
    protected void print() {
        System.out.println("--------------" + getName() + "--------------");
        //遍歷 organizationComponents
        for (OrganizationComponent organizationComponent : organizationComponents) {
            organizationComponent.print();
        }
    }
}

 3、容器構件 --> 學院類

package designMode.advance.composite;

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

public class College extends OrganizationComponent {
    //List 中 存放的Department
    List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>();

    // 構造器
    public College(String name, String des) {
        super(name, des);
    }

    // 重寫add
    @Override
    protected void add(OrganizationComponent organizationComponent) {
        //  將來實際業務中,Colleage 的 add 和  University add 不一定完全一樣
        organizationComponents.add(organizationComponent);
    }

    // 重寫remove
    @Override
    protected void remove(OrganizationComponent organizationComponent) {
        organizationComponents.remove(organizationComponent);
    }

    @Override
    public String getName() {
        return super.getName();
    }

    @Override
    public String getDes() {
        return super.getDes();
    }

    // print方法,就是輸出University 包含的學院
    @Override
    protected void print() {
        System.out.println("--------------" + getName() + "--------------");
        //遍歷 organizationComponents
        for (OrganizationComponent organizationComponent : organizationComponents) {
            organizationComponent.print();
        }
    }
}

4、葉子節點 --> 專業類

package designMode.advance.composite;

public class Department extends OrganizationComponent {
    //沒有集合
    public Department(String name, String des) {
        super(name, des);
    }

    //add , remove 就不用寫了,因爲他是葉子節點
    @Override
    public String getName() {
        return super.getName();
    }

    @Override
    public String getDes() {
        return super.getDes();
    }

    @Override
    protected void print() {
        System.out.println(getName());
    }
}

5、測試類

package designMode.advance.composite;

public class Client {
    public static void main(String[] args) {
        //從大到小創建對象 學校
        OrganizationComponent university = new University("清華大學", " 中國頂級大學 ");

        //創建 學院
        OrganizationComponent computerCollege = new College("計算機學院", " 計算機學院 ");
        OrganizationComponent infoEngineercollege = new College("信息工程學院", " 信息工程學院 ");


        //創建各個學院下面的系(專業)
        computerCollege.add(new Department("軟件工程", " 軟件工程不錯 "));
        computerCollege.add(new Department("網絡工程", " 網絡工程不錯 "));
        computerCollege.add(new Department("計算機科學與技術", " 計算機科學與技術是老牌的專業 "));

        //
        infoEngineercollege.add(new Department("通信工程", " 通信工程不好學 "));
        infoEngineercollege.add(new Department("信息工程", " 信息工程好學 "));

        //將學院加入到 學校
        university.add(computerCollege);
        university.add(infoEngineercollege);

        university.print();
        //infoEngineercollege.print();
    }
}

六、Java集合類HashMap 源碼分析

HashMap 提供了putAll方法,可以將另一個Map對象放入自己的存儲空間中,如有相同的key則會覆蓋之前的key值所對應的value值。

1、代碼實例

package designMode.advance.composite;

import java.util.HashMap;
import java.util.Map;

public class HashMapComposite {
    public static void main(String[] args) {
        Map<Integer,String> universityMap = new HashMap<>();
        universityMap.put(1,"清華大學");
        universityMap.put(2,"北京大學");
        universityMap.put(3,"遼寧石油化工大學");
        System.out.println("universityMap: " + universityMap);
        Map<Integer,String> collegeMap = new HashMap<>();
        collegeMap.put(1,"計算機學院");
        collegeMap.put(4,"信息工程學院");
        System.out.println("collegeMap: " + collegeMap);
        universityMap.putAll(collegeMap);
        System.out.println("universityMap.putAll(collegeMap),"+universityMap);
    }
}

2、控制檯輸出

3、源碼分析

putAll接收的參數爲父類Map類型,所以hashmap是一個容器類,map的子類爲葉子類,當然如果map的其它子類也實現了putAll方法,那麼他們既是容器類,又都是葉子類;

同理,ArrayList 中的 addAll(Collection<? extends E> c) 方法也是一個組合模式的應用;

七、Mybatis SqlNode中的組合模式

MyBatis 的強大特性之一便是它的動態SQL,其通過 if, choose, when, otherwise, trim, where, set, foreach 標籤,可組合成非常靈活的SQL語句,從而提高開發人員的效率。

動態SQL – IF

<select id="findActiveBlogLike"  resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’ 
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>
</select>

動態SQL – choose, when, otherwise

<select id="findActiveBlogLike"  resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
</select>

動態SQL – where

<select id="findActiveBlogLike"  resultType="Blog">
  SELECT * FROM BLOG 
  <where> 
    <if test="state != null">
         state = #{state}
    </if> 
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>

動態SQL – foreach

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT * FROM POST P WHERE ID in
  <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
        #{item}
  </foreach>
</select>

Mybatis在處理動態SQL節點時,應用到了組合設計模式,MyBatis會將映射文件中定義的靜態SQL節點、文本節點等解析成對應的SqlNode實現,形成樹形結構。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章