Java設計模式之(三)——建造者模式

YSOcean發表於2021-11-19

1、什麼是建造者模式

Separate the construction of a complex object from its representation so that the same construction process can create different representations.

將一個複雜物件的構建與它的表示分離, 使得同樣的構建過程可以建立不同的表示。

說人話:將構造複雜物件的過程和組成物件的部件解耦。就像攢電腦一樣,不管什麼品牌的配件,只要兼
容就可以裝上;同樣,一樣的配件,可以有好多組裝的方式。更直接點就是同一個類,通過內部不同屬性狀態構造不同的物件。

2、建造者模式定義

image-20210831081701593

在建造者模式中,有 4 個定義:

①、Product(產品類) :我們具體需要生成的類物件

②、Builder(抽象建造者類):為我們需要生成的類物件,構建不同的模組屬性,即:公開構建產品類的屬性,隱藏產品類的其他功能。

③、ConcreteBuilder(具體建造者類):實現抽象類定義的所有方法,並返回一個組建好的物件。

④、Director(導演類):確定構建我們的類物件具體有哪些模組屬性,在實際應用中可以不需要這個角色,直接通過client處理。

3、例項

比如我們去買車,一般同一輛車會有多個版本,根據配置不一樣,分為經典版、舒適版、豪華版等,比如經典版是手動擋手動座椅,舒適版是自動擋全景天窗等。

public class Car {
    // 車名稱
    private String name;
    // 自動擋
    private String automaticCatch;
    // 手動擋
    private String manualTransmission;
    // 全景天窗
    private String panoramicSunroof;
    // 自動座椅
    private String automaticSeat;
    // 手動座椅
    private String manualSeat;
    // 倒車影像
    private String reversingImage;

    //省略get/set方法
}

3.1 普通實現

public class GeneralTest {
    public Car getCarInstance(String carName){
        Car car = new Car();
        if("經典版".equals(carName)){
            car.setName("經典版");
            car.setManualTransmission("手動擋");
        }else if("舒適版".equals(carName)){
            car.setName("舒適版");
            car.setAutomaticCatch("自動擋");
            car.setManualSeat("手動座椅");
        }else if("豪華版".equals(carName)){
            car.setName("豪華版");
            car.setAutomaticCatch("自動擋");
            car.setAutomaticSeat("自動座椅");
            car.setReversingImage("倒車影像");
            car.setPanoramicSunroof("全景天窗");
        }else{
            throw new IllegalArgumentException("carName is error: carName="+carName);
        }
        return car;
    }
}

注意,並不是說高版本汽車一定具有低版本所有配置,比如舒適版配置是手動座椅,豪華版是自動座椅,而且不同版本之間配置有交叉。

從上面可以看出,根據汽車型別,我們可以建立相應配置的汽車,但其實汽車的配置是有很多的,種類一旦多了,上面的程式碼就會顯得很臃腫,也不好維護,於是我們用建造者模式來重構。

3.2 建造者模式實現

①、建立抽象建造者類

public abstract class CarBuilder {

    public abstract Car buildClassic();

    public abstract Car buildComfortable();

    public abstract Car buildLuxury();

}

②、建立具體建造者類。對抽象建造者類的抽象方法進行實現賦值,達到我們所需要的結果。

public class CarConcreteBuilder extends CarBuilder{

    @Override
    public Car buildClassic() {
        Car car = new Car();
        car.setName("經典版");
        car.setManualTransmission("手動擋");
        return car;
    }

    @Override
    public Car buildComfortable() {
        Car car = new Car();
        car.setName("舒適版");
        car.setAutomaticCatch("自動擋");
        car.setManualSeat("手動座椅");
        return car;
    }

    @Override
    public Car buildLuxury() {
        Car car = new Car();
        car.setName("豪華版");
        car.setAutomaticCatch("自動擋");
        car.setAutomaticSeat("自動座椅");
        car.setReversingImage("倒車影像");
        car.setPanoramicSunroof("全景天窗");
        return car;
    }
}

③、建立我們的導演類,指導我們怎麼去建立物件

public class CarDirector {
    private CarBuilder carBuilder;

    public CarDirector(CarBuilder carBuilder){
        this.carBuilder = carBuilder;
    }

    public Car classicConstruct(){
        return carBuilder.buildClassic();
    }

    public Car comfortableConstruct(){
        return carBuilder.buildComfortable();
    }

    public Car luxuryConstruct(){
        return carBuilder.buildLuxury();
    }
}

④、測試

public class BuilderTest {
    public static void main(String[] args) {
        CarBuilder carBuilder = new CarConcreteBuilder();
        CarDirector carDirector = new CarDirector(carBuilder);
        Car classicCar = carDirector.classicConstruct();
        System.out.println(classicCar);
        Car comfortableCar = carDirector.comfortableConstruct();
        System.out.println(comfortableCar);
    }
}

另外,對於不同配置之間有互斥關係,比如有了手動擋,就不可能有自動擋,屬性之間的關係我們也可以在具體建造者類 CarConcreteBuilder 進行設定。

4、與工廠模式區別

前面我們介紹工廠模式時說了由工廠類來負責建立物件,而建造者模式也是讓具體建造者類負責建立物件,那這兩者有什麼區別呢?

實際上工廠模式是用來建立不同但是相關型別的物件(繼承同一父類或者介面的一組子類),由給定的引數來決定建立哪種型別的物件。而建造者模式是用來建立一種型別的複雜物件,通過設定不同的可選引數,“定製化”地建立不同的物件。

有這樣一個例子可以形象的解釋:

顧客走進一家餐館點餐,我們利用工廠模式,根據使用者不同的選擇,來製作不同的食物,比如披薩、漢堡、沙拉。對於披薩來說,使用者又有各種配料可以定製,比如乳酪、蕃茄、起司,我們通過建造者模式根據使用者選擇的不同配料來製作披薩。

5、建造者模式優點

①、封裝性

使用建造者模式可以使客戶端不必知道產品內部組成的細節, 如例子中我們就不需要關心每一種版本汽車內部是如何實現的, 產生的物件型別就是Car。

②、建造者獨立,容易擴充套件

其實對於上面例子中的 CarConcreteBuilder 類,有三個方法,分別構造經典版、舒適版、豪華版汽車,每個方法內部是不受影響的,或者我們還可以直接把這一個類拆成三個類。

③、便於控制細節風險

由於具體每個建造者過程是獨立的,因此可以對過程更加細化,而不會對其它模組產生影響。

6、建造者模式使用場景

①、相同的方法, 不同的執行順序, 產生不同的事件結果時, 可以採用建造者模式。

②、多個部件或零件, 都可以裝配到一個物件中, 但是產生的執行結果又不相同時, 則可以使用該模式。

③、產品類非常複雜, 或者產品類中的呼叫順序不同產生了不同的效能, 這個時候使用建造者模式非常合適。

相關文章