設計模式-建造者模式

最近在項目中寫bug的時候發現,項目中的公共Dialog管理類是這樣的:html

 

 

致使每一次增長一種類型的 Dialog 就要增長一個構造函數來實現,長此以往這個類屬性也愈來愈多,構造參數的種類也愈來愈多,這個類的初衷是爲了封裝系統AlterDialog的使用,讓一些相一樣式的Dialog能夠用最簡單的樣式建立,無奈UI樣式隨着產品的迭代,愈來愈多,這種單純的封裝有點讓人力不從心了。編程

本文將介紹一種簡單的設計模式「建造者模式」。也許它能夠很好的解決生產中相似上述描述的狀況。設計模式

建造者模式的組成部分

我所理解的設計模式思想,自己就是用於解決重複代碼封裝的一種思想。是前輩們給咱們留下的經驗。而「書本中的建造者模式」是下邊的下邊這樣子的:ide

 

 

能夠看出設計模式由四部分組成:函數

  1. Product: 產品類所描述的是咱們最終想要的到的結果統稱,例如一個封裝好的帶有多選按鈕列表的 Dialog。
  2. Builder: 建造者的接口定義,他定義了建造某種產品類須要的步驟,但不提供實現。
  3. ConcreteBuilder: 建造者的實現類,繼承自 Builder 提供一種建立類型的具體步驟,是咱們封裝的拓展對象,好比項目以前只有雙按鈕的對話框,如今咱們有一種帶多選功能的對畫框須要建立,咱們就能夠新建一個 ConcreteBuilder 繼承自Builder,來完成對多選框Dialog的建立工做,而無序改動前二者。
  4. Director: Builder 類的建立者,由他來爲各類 Builder 來賦值屬性,Director隔離了建造者實現類與實際客戶端建立,讓實際對象的建立只關注於對象的屬性。

建造者模式的例子

下面經過一個抽象派的 Dota 英雄建立過程,來看下上述四部分是怎麼工做的:學習

首先定一個 DotaHero 類這個類是咱們最終的產品類也就是 Product,他能夠理解爲一個超類,具體實現決定於建造者如何建造。ui

public class DotaHero {
    //英雄分類 智力 力量 和 敏捷
    public static final int HERO_INTELLECTUAL = 1;
    public static final int HERO_POWEER = 2;
    public static final int HERO_AGLIE = 3;
    @IntDef(value = {HERO_AGLIE, HERO_POWEER, HERO_INTELLECTUAL})
    public @interface HeroType {
    }
    //英雄屬性
    private String heroName;
    private String heroDes;
    private int heroType;
    private HashMap<String, String> heroSkills;

    //施放置頂技能
    public void executeSkill(String key) {
        if (heroSkills.containsKey(key)) {
            System.out.println("施放 " + key + " 技能: " + heroSkills.get(key));
        }
    }
    ..... //省略不少的get set
}
複製代碼

DotaHero 是建造者建造的目標,這裏定義的屬性和方法是最全的,不一樣的建造者,經過不一樣的構建步驟,爲屬性賦值獲得最終的不一樣英雄。this

下面咱們來定一個一個抽象的建造者建立類,該類定義了全部建造者須要的屬性,實現類能夠任意擴展。spa

public abstract class HeroBuilder {
    //最終建造的對象
    protected DotaHero hero;
    
    public HeroBuilder() {
        //這裏在構造函數中就初始化了對象,其實最好的方法是將其放到build方法中。
        hero = new DotaHero();
    }

    
    public HeroBuilder setHeroName(String name) {
        hero.setHeroName(name);
        return this;
    }

    public HeroBuilder setHeroDes(String des) {
        hero.setHeroDes(des);
        return this;
    }


    public HeroBuilder addHeroSkill(String keyName, String skill) {
        hero.addHeroSkill(keyName, skill);
        return this;
    }
    
    //定義了英雄類型的抽象方法,須要子類去實現
    protected abstract HeroBuilder setHeroType();
    
    public DotaHero build() {
        return hero;
    }
}
複製代碼

接下來咱們來定義Dota中的英雄建造者,你們都知道,Dota 中英雄有 智力,敏捷,力量三種,因此咱們這裏定義三種建造者用來構建者三種類型的英雄。設計

//智力
public class AglieHeroBuilder extends HeroBuilder {
    @Override
    protected HeroBuilder setHeroType() {
        hero.setHeroType(DotaHero.HERO_AGLIE);
        return this;
    }
}
//敏捷
public class IntellectualHeroBuilder extends HeroBuilder {
    @Override
    protected HeroBuilder setHeroType() {
        hero.setHeroType(DotaHero.HERO_INTELLECTUAL);
        return this;
    }
}
//力量
public class PowerHeroBuilder extends HeroBuilder {
    @Override
    protected HeroBuilder setHeroType() {
        hero.setHeroType(DotaHero.HERO_POWEER);
        return this;
    }
}
複製代碼

上述列舉了三種建造者,這裏只作了抽象方法的實現,實際生產中,子類能夠根據須要拓展獨有屬性。

完成上述工做後,咱們就已經可以使用建造者來建立咱們須要的對象了。但建造者模式中推薦咱們將實際對象的生產的工做不要暴露給客戶端,須要經過建立者(建立建造者的類)來隔離建造者和客戶端,這樣客戶端只須要聲明我須要一個什麼樣的建造者,來建立一個什麼樣的對象就能夠了。這樣當之後出現了新的建造者類型的時候,客戶端仍舊只須要關注上述兩點。

下面咱們來看下建立者的定義:

public class Director {

    private HeroBuilder builder;
    //構造函數1 直接在外界定義好某類型的 Builder 傳入
    public Director(@NonNull HeroBuilder builder) {
        this.builder = builder;
    }

    public DotaHero getAHero() {
        if (builder != null) {
            return builder.build();
        }
        return null;
    }
}
複製代碼

上述代碼暴露的個構造方法來建立建造者。他目前所作的工做就是獲取建造者或者根據類型建立建造者,經過getAHero方法來得到一個生產對象。

什麼時候該應用建造者模式

經過上述的例子咱們能夠很好的理解,第一部分建造者模式的各組成部分的做用以及意義。那麼在實際生產過程當中咱們什麼時候該應用建造者模式呢?

在如下狀況下可使用建造者模式:

  • 須要生成的產品對象有複雜的內部結構,這些產品對象一般包含多個成員屬性。
  • 須要生成的產品對象的屬性相互依賴,須要指定其生成順序。
  • 建造者對象的建立過程獨立於建立該對象的類。在建造者模式中引入了指揮者類,將建立過程封裝在指揮者類中,而不在建造者類中。
  • 隔離複雜對象的建立和使用,並使得相同的建立過程能夠建立不一樣的產品。

建造者模式的意義在於,建造者模式是一步一步建立一個複雜的對象,它容許用戶只經過指定複雜對象的類型和內容就能夠構建它們,用戶不須要知道內部的具體構建細節。

##建造者模式的優缺點

建造者模式的優勢:

  1. 在建造者模式中, 客戶端沒必要知道產品內部組成的細節,將產品自己與產品的建立過程解耦,使得相同的建立過程能夠建立不一樣的產品對象。

  2. 每個具體建造者都相對獨立,而與其餘的具體建造者無關,所以能夠很方便地替換具體建造者或增長新的具體建造者, 用戶使用不一樣的具體建造者便可獲得不一樣的產品對象 。

  3. 增長新的具體建造者無須修改原有類庫的代碼,建立者類針對抽象建造者類編程,系統擴展方便,符合「開閉原則」。

建造者模式的缺點:

  1. 建造者模式所建立的產品通常具備較多的共同點,其組成部分類似,若是產品之間的差別性很大,則不適合使用建造者模式,所以其使用範圍受到必定的限制。
  2. 若是產品的內部變化複雜,可能會致使須要定義不少具體建造者類來實現這種變化,會致使具體建造者數量變得不少。

總結

經過上文的敘述相信你們已經知道什麼是建造者模式了,咱們也清楚了建造者模式定義步驟,可是實際開發中,若是一個產品類,變化的範圍僅僅是屬性不一樣或者構造順序不一樣,那麼一個建造者實現類就能夠完成工做,那麼咱們能夠省略後兩個角色,也就是說 Builder 的類兼職完成步驟2和步驟3。

學習設計模式,筆者認爲最好的學習方法就是應用,本文中列舉的例子可能過於簡單,離掌握還差的遠,下一片文章將會帶領你們瞭解我對我司項目中 Dialog 建立封裝的過程,從實踐中來理解。

參考連接:

建造者模式

設計模式之嬋 第2版

相關文章
相關標籤/搜索