咱們你們可能都會開小汽車,可是當你獲得一輛小汽車的時候,你能夠用它馳騁馬路,可是你知道它組件複雜的構造過程嗎,並不知道。而咱們今天要講的建造者模式其實就是複雜的建立型模式
,客戶端無需知道複雜對象的內部組成和裝配方式,只須要知道建造者的類型便可
。它關注的是一步步的建立獨立的複雜對象,不一樣的具體構造者定義不一樣的建立過程
。其定義以下:java
建造者模式(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(實際的建造者)
ide
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();
}
}
複製代碼
結構圖:ui
案例代碼:this
產品對象汽車
spa
// 產品對象
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類去指導如何一步步的生成部件,返回完整對象。
簡單的理解:抽象工廠模式就是汽車配件生產廠,生產不一樣類型的汽車配件,而建造者模式就是一個汽車組裝廠,組裝配件返回完整汽車。
號外號外:
java架構師小密圈
,回覆1**:獲取2Tjava架構師必備乾貨 ,另外:小夥伴能夠回覆任意想學的技術,能夠免費幫你搜尋
,其實咱們還須要學不少!!!!!!
公衆號:分享系列好文章
交流羣:一塊兒奔着java架構師努力