23種設計模式(4):建造者模式

1.概念

定義:建造者模式是把一個物體的構造過程與其本身進行分離,使得相同的構造過程可以創建不同的物體,簡而言之,就是構造過程複用

想象一下我們玩角色扮演類遊戲的時候,剛開始電腦會讓你創建角色,比如選擇人物的職業、頭髮顏色、性別,最後輸入一個騷氣的暱稱,這個創建的過程就算完成了!

2.爲什麼要用這個建造者模式呢

答:它是一種創建對象的軟件設計模式,旨在提高對象構造器的伸縮性

不用這個模式,我們的對象伸縮性瓶頸是哪裏呢?看下面的代碼就會明白:

public Hero(Profession profession, String name) {
}

如您所見,構造函數參數的數量如果再增加,那麼很快就會失控,因爲同樣類型的參數,我們可能難以理解參數的排列。另外,如果將來想添加更多選項,則此參數列表可能會繼續增長。這也被稱爲伸縮構造函數反模式

3.程式範例

還是以遊戲中創建英雄的例子來說吧,先來完成我們英雄的一些初始化屬性。

/**
 * 職業的枚舉類
 *
 * @author suvue
 * @date 2020/1/12
 */
public enum Profession {

    /**
     * 戰士
     */
    WARRIOR,

    /**
     * 刺客
     */
    THIEF,
    /**
     * 法師
     */
    MAGE,
    ;

    @Override
    public String toString() {
        return name().toLowerCase();
    }
}

下面是英雄的頭髮顏色枚舉。

/**
 * 頭髮顏色
 *
 * @author suvue
 * @date 2020/1/12
 */
public enum HairColor {
    /**
     * 紅髮
     */
    RED,
    /**
     * 棕發
     */
    BROWN,
    /**
     * 黑髮
     */
    BLACK,
    ;

    @Override
    public String toString() {
        return name().toLowerCase();
    }

}

下面是英雄持有的武器枚舉了。

import lombok.Data;

/**
 * 英雄
 *
 * @author suvue
 * @date 2020/1/12
 */
@Data
public class Hero {
    private final HairColor hairColor;
    private final Profession profession;
    private final Weapon weapon;
    private final String name;

    /**
     * 我們傳進來一個通用的建造器
     */
    public Hero(Builder builder) {
        this.hairColor = builder.hairColor;
        this.profession = builder.profession;
        this.weapon = builder.weapon;
        this.name = builder.name;
    }

    /**
     * 這是一個靜態內部類,我們來實現這個通用建造器
     */
    public static class Builder {
        private HairColor hairColor;
        private final Profession profession;
        private Weapon weapon;
        private final String name;

        /**
         * 建造器的構造函數 我們要求職業和暱稱必填
         */
        public Builder(Profession profession, String name) {
            if (profession == null || name == null) {
                throw new IllegalArgumentException("初始化參數爲空");
            }
            this.profession = profession;
            this.name = name;
        }

        public Builder withHairColor(HairColor hairColor) {
            this.hairColor = hairColor;
            return this;
        }

        public Builder withWeapon(Weapon weapon) {
            this.weapon = weapon;
            return this;
        }

        public Hero build() {
            return new Hero(this);
        }


    }

}

我們來看看具體是怎麼使用的吧

public class Client {
    public static void main(String[] args) {
        //創建一個拿着法杖的紅髮魔法師角色
        Hero mage = new Hero
                .Builder(Profession.MAGE, "法師")
                .withHairColor(HairColor.RED)
                .withWeapon(Weapon.ROD)
                .build();
        System.out.println(mage.toString());

        //創建一個拿着劍的黑髮戰士角色
        Hero warrior = new Hero.Builder(Profession.WARRIOR, "戰士")
                .withHairColor(HairColor.BLACK)
                .withWeapon(Weapon.SWORD)
                .build();
        System.out.println(warrior.toString());
    }
}

創建過程是不是很簡單呢,而且以後要是擴展的話,直接在Hero類中加一個類似於withWeapon()的方法就行啦

前輩們總結的經驗,都乃是精髓呀!

4.建造者模式在框架中的使用

4.1JDK1.8源碼中的建造者模式

StringBuilder與StringBuffer的父抽象類:AbstractStringBuilder 我們截取一部分關鍵源碼看一下。

 public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }

4.2 spring中的建造者模式

摘選 BeanDefinitionBuilder 類的部分源碼。

package org.springframework.beans.factory.support;
public final class BeanDefinitionBuilder {
    //獲取builder對象的靜態方法
    public static BeanDefinitionBuilder genericBeanDefinition() {
		return new BeanDefinitionBuilder(new GenericBeanDefinition());
	}
    
    public BeanDefinitionBuilder setParentName(String parentName) {
		this.beanDefinition.setParentName(parentName);
		return this;
	}
    
    public BeanDefinitionBuilder setFactoryMethod(String factoryMethod) {
		this.beanDefinition.setFactoryMethodName(factoryMethod);
		return this;
	}
    
    public BeanDefinitionBuilder setFactoryMethodOnBean(String factoryMethod, String factoryBean) {
		this.beanDefinition.setFactoryMethodName(factoryMethod);
		this.beanDefinition.setFactoryBeanName(factoryBean);
		return this;
	}
    //可以有很多個set方法靈活性的爲屬性賦值
    //...
    
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章