建造者模式 一:建造者概述 我們大家可能都會開小汽車,但是當你得到一輛小汽車的時候,你可以用它馳騁馬路,但是你知道它組件複雜的構造過程嗎,並不知道。而我們今天要講的建造者模式其實就是 ,`客戶端無需知道複雜對象的內部組成和裝配方式,只需要知道建造者的類型即可 一步步的創建獨立的複雜對象,不同的具體構 ...
建造者模式
一:建造者概述
我們大家可能都會開小汽車,但是當你得到一輛小汽車的時候,你可以用它馳騁馬路,但是你知道它組件複雜的構造過程嗎,並不知道。而我們今天要講的建造者模式其實就是複雜的創建型模式
,客戶端無需知道複雜對象的內部組成和裝配方式,只需要知道建造者的類型即可
。它關註的是一步步的創建獨立的複雜對象,不同的具體構造者定義不同的創建過程
。其定義如下:
建造者模式(Builder Pattern):將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。建造者模式是一種對象創建型模式
二:建造者結構圖
在結構圖中包含以下幾個角色:
Builder(抽象建造者)
: 是一個抽象介面,為了創建一個產品對象的各個部件 ,主要有兩類方法,一類是buildXX,用於創建複雜對象的各個部件,一類是getProduct,用於返回覆雜對象。ActualBuilder(實際的建造者)
:實現Builder介面,實現各個部件的建造方法,返回創建好的複雜對象。Product(產品角色)
:被構建出來的複雜對象,包含多個部件。Director(指揮者)
:負責安排部件創建的順序,客戶端一般只和指揮者
進行交互,在客戶端確定實際的建造者
,然後通過指揮者的構造函數或者setter方法
將該對象傳入到指揮者
類中。
三:典型代碼
Builder(抽象建造者)
public abstract class Builder {
// 創建產品對象
protected Product product = new Product();
// 具體部件建造過程在ActualBuilder中實現
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
// 定義工廠方法,返回一個完整產品對象
public Product getProduct(){
return product;
}
}
ActualBuilder(實際的建造者)
public class ActualBuilder extends Builder {
@Override
public void buildPartA() {
product.setPartA("設置部件A");
}
@Override
public void buildPartB() {
product.setPartA("設置部件B");
}
@Override
public void buildPartC() {
product.setPartA("設置部件C");
}
}
Product(產品角色)
// 產品對象
public class Product {
// 定義部件
private String partA;
private String partB;
private String partC;
public String getPartA() {
return partA;
}
public void setPartA(String partA) {
this.partA = partA;
}
public String getPartB() {
return partB;
}
public void setPartB(String partB) {
this.partB = partB;
}
public String getPartC() {
return partC;
}
public void setPartC(String partC) {
this.partC = partC;
}
}
Director(指揮者)
public class Director {
private Builder builder;
// 方式一:通過構造函數設置實際的構造者
// 傳入類型是基類,面向抽象編程,符合里氏替換原則
public Director(Builder builder) {
this.builder=builder;
}
// 方式二:通過setter方法設置實際的構造者
public void setBuilder(Builder builder) {
this.builder=builder;
}
// 構建複雜產品對象
public Product construct(){
// 指揮者可以決定產品部件的構建順序
builder.buildPartC();
builder.buildPartA();
builder.buildPartB();
return builder.getProduct();
}
}
四:組裝小汽車案例
結構圖:
案例代碼:
產品對象汽車
// 產品對象
public class Car {
// 定義部件
// 輪胎
private String tire;
// 座椅
private String seat;
// 發動機
private String engine;
public String getTire() {
return tire;
}
public void setTire(String tire) {
this.tire = tire;
}
public String getSeat() {
return seat;
}
public void setSeat(String seat) {
this.seat = seat;
}
public String getEngine() {
return engine;
}
public void setEngine(String engine) {
this.engine = engine;
}
}
汽車的抽象建造者
public abstract class CarBuilder {
// 創建汽車
protected Car car = new Car();
// 創建輪胎
public abstract void buildTire();
// 創建座椅
public abstract void buildSeat();
// 創建發動機
public abstract void buildEngine();
// 定義工廠方法,返回一個完整汽車
public Car getCar(){
return car;
}
}
具體建造者:大眾
// 大眾汽車
public class DaZhongCarBuilder extends CarBuilder {
@Override
public void buildTire() {
car.setTire("大眾輪胎");
}
@Override
public void buildSeat() {
car.setSeat("大眾座椅");
}
@Override
public void buildEngine() {
car.setEngine("大眾發動機");
}
}
具體建造者:豐田
// 豐田汽車
public class FenTianCarBuilder extends CarBuilder {
@Override
public void buildTire() {
getCar().setTire("豐田輪胎");
}
@Override
public void buildSeat() {
getCar().setSeat("豐田座椅");
}
@Override
public void buildEngine() {
getCar().setEngine("豐田發動機");
}
}
指揮者
public class CarDirector {
private CarBuilder carBuilder;
// 方式一:通過構造函數設置實際的構造者
// 傳入類型是基類,面向抽象編程,符合里氏替換原則
public CarDirector(CarBuilder carBuilder) {
this.carBuilder = carBuilder;
}
// 方式二:通過setter方法設置實際的構造者
public void setCarBuilder(CarBuilder carBuilder) {
this.carBuilder = carBuilder;
}
// 構建複雜產品對象
public Car construct(){
// 指揮者可以決定產品部件的構建順序
carBuilder.buildTire();
carBuilder.buildSeat();
carBuilder.buildEngine();
return carBuilder.getCar();
}
}
客戶端
public class Client {
public static void main(String[] args) {
// 創建一個實際車的構造者
CarBuilder carBuilder = new FenTianCarBuilder();
// 創建指揮者
CarDirector carDirector = new CarDirector(carBuilder);
// 構建出完整產品
Car product = carDirector.construct();
}
}
說明:整個流程其實很簡單,指揮者指導構建者一步步的構造完整產品,根據指揮者定義的構造過程可以創建出完全不同的產品
。
五:如何控制構造者不生產某個部件
我們發現構造整個產品的構造過程都是按照指揮者構建部件的順序逐步構建,但是可能有的具體的構造者不需要某個部件,比如大眾汽車不需要座椅(當然這是不可能的),那麼它就不需要調用buildSeat()方法。為瞭解決這個問題,我們引入一個鉤子方法
,通常鉤子方法
名為isXXX()
,其定義在抽象構造者類中,我們可以定義一個isSeat()的方法,來判斷是否需要座椅,併為之提供一個預設實現為false。
抽象構造者中設置是否需要座椅的鉤子方法
public abstract class CarBuilder {
// 創建汽車
protected Car car = new Car();
// 創建輪胎
public abstract void buildTire();
// 創建座椅
public abstract void buildSeat();
// 創建發動機
public abstract void buildEngine();
// 定義一個鉤子方法,是否需要座椅, 預設為true
public boolean isSeat(){
return true;
}
// 定義工廠方法,返回一個完整汽車
public Car getCar(){
return car;
}
}
具體構造者覆蓋鉤子方法,返回false,表示不需要座椅
// 大眾汽車
public class DaZhongCarBuilder extends CarBuilder {
@Override
public void buildTire() {
car.setTire("大眾輪胎");
}
@Override
public void buildSeat() {
car.setSeat("大眾座椅");
}
@Override
public void buildEngine() {
car.setEngine("大眾發動機");
}
@Override
public boolean isSeat() {
return false;
}
}
指揮者根據具體構造者的需求構建產品
public class CarDirector {
private CarBuilder carBuilder;
// ........省略部分代碼
// 構建複雜產品對象
public Car construct(){
// 指揮者可以決定產品部件的構建順序
carBuilder.buildTire();
// 鉤子方法 用來確定是否需要構建某個部件
if(carBuilder.isSeat()){
// 表示需要座椅的時候才會構建
carBuilder.buildSeat();
}
carBuilder.buildEngine();
return carBuilder.getCar();
}
}
六:建造者模式總結
優點
- 客戶端不需要知道具體創建對象的細節,將產品本身和產品的創建過程解耦,相同的創建過程可以創建出不同的產品對象。
- 每個具體建造者相對獨立,增加新的具體建造者不會影響現有的類庫代碼,符合開閉原則。
- 可以採用鉤子方法精確的控制某個具體建造者是否需要某個部件。可以針對的控制產品構建流程。
缺點
- 如果產品之間的差異性較大,那麼即使使用鉤子方法來控制,那也是極其麻煩,且公共介面很難抽象。非常不適合。
適用場景
- 需要生成的產品對象有複雜的內部結構,這些產品對象通常包含多個成員屬性。
- 需要生成的產品對象的屬性相互依賴,需要指定其生成順序。
- 對象的創建過程獨立於創建該對象的類。在建造者模式中通過引入了指揮者類,將創建過程封裝在指揮者類中,而不在建造者類和客戶類中。
- 隔離複雜對象的創建和使用,並使得相同的創建過程可以創建不同的產品。
七:抽象工廠模式和建造者模式的區別
抽象工廠模式返回的是一系列相關的產品,而建造者模式返回的是一個具體的完整對象。
抽象工廠模式的客戶端是通過選擇具體工廠來生成所需要的對象,而建造者模式是通過Director類去指導如何一步步的生成部件,返回完整對象。
簡單的理解:抽象工廠模式就是汽車配件生產廠,生產不同類型的汽車配件,而建造者模式就是一個汽車組裝廠,組裝配件返回完整汽車。
參考:https://blog.csdn.net/lovelion/article/details/7426015