建造者模式
建造者模式(Builder),又叫生成器模式,是一種對象構建模式。它將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
建造者模式可以將一個產品的內部表象和產品的生成過程分割開來,從而可以使一個建造過程生成具有不同的內部表象的產品對象。如果我們用了建造者模式,那麼用戶就只需指定需要建造的類型就可以得到它們,而具體建造的過程和細節就不需要知道了。
建造者模式解析
角色介紹
- Product(產品角色):具體產品對象。
- Builder(抽象建造者):是爲創建一個 Product 對象的各個部件指定的抽象接口。
- ConcreteBuilder(具體建造者):實現 Builder 接口,構建和裝配各個部件。
- Director(指揮者):是構建一個使用 Builder 接口的對象。它主要是用於創建一個複雜的對象。 它主要有兩個作用,一是隔離了客戶與對象的生產過程,二是負責控制產品對象的生產過程。
建造者模式基本代碼
- Product 類:產品類,由多個部件組成。
public class Product {
private List<String> parts = new ArrayList<>();
/**
* 添加部件
*/
public void add(String part) {
this.parts.add(part);
}
/**
* 列舉所有部件
*/
public void show() {
this.parts.forEach(System.out::println);
}
}
- Builder 類:抽象建造者類,確定產品由兩個部件 PartA 和 PartB 組成,並聲明一個得到產品結果的方法 getResult()。
public interface Builder {
void buildPartA();
void buildPartB();
Product getResult();
}
- ConcreteBuilderA 類:具體建造者 A。
public class ConcreteBuilderA implements Builder {
private Product product = new Product();
@Override
public void buildPartA() {
product.add("X");
}
@Override
public void buildPartB() {
product.add("Y");
}
@Override
public Product getResult() {
return product;
}
}
- ConcreteBuilderB 類:具體建造者 B。
public class ConcreteBuilderB implements Builder {
private Product product = new Product();
@Override
public void buildPartA() {
product.add("M");
}
@Override
public void buildPartB() {
product.add("N");
}
@Override
public Product getResult() {
return product;
}
}
- Director 類:指揮者類。
public class Director {
public void build(Builder builder) {
builder.buildPartA();
builder.buildPartB();
}
}
- Main 類
public class Main {
public static void main(String[] args) {
Director director = new Director();
ConcreteBuilderA builderA = new ConcreteBuilderA();
ConcreteBuilderB builderB = new ConcreteBuilderB();
director.build(builderA);
Product resultA = builderA.getResult();
resultA.show();
director.build(builderB);
Product resultB = builderB.getResult();
resultB.show();
}
}
示例
需求:蓋房子,過程有打樁、砌牆、封頂。房子有各種各樣的,比如普通房,高樓,別墅,各種房子的過程雖然一樣,但是要求不相同的。
傳統寫法
/**
* House
*/
public class House {
private Integer length;
private Integer width;
private Integer high;
public Integer getLength() {
return length;
}
public void setLength(Integer length) {
this.length = length;
}
public Integer getWidth() {
return width;
}
public void setWidth(Integer width) {
this.width = width;
}
public Integer getHigh() {
return high;
}
public void setHigh(Integer high) {
this.high = high;
}
@Override
public String toString() {
return "House{" +
"length=" + length +
", width=" + width +
", high=" + high +
'}';
}
}
/**
* 普通房子
*/
public class CommonHouseBuilder {
public House build() {
House house = new House();
house.setLength(50);
house.setWidth(20);
house.setHigh(5);
return house;
}
}
/**
* 高房子
*/
public class HighHouseBuilder {
public House build() {
House house = new House();
house.setLength(60);
house.setWidth(30);
house.setHigh(6);
return house;
}
}
/**
* Main
*/
public class Main {
public static void main(String[] args) {
// 普通房子
CommonHouseBuilder commonHouseBuilder = new CommonHouseBuilder();
House commonHouse = commonHouseBuilder.build();
System.out.println(commonHouse.toString());
// 高房子
HighHouseBuilder highHouseBuilder = new HighHouseBuilder();
House highHouse = highHouseBuilder.build();
System.out.println(highHouse.toString());
}
}
上面這種寫法將建造過程和表象都放在了一起,耦合性很強,而且普通房子和高房子的建造過程是一樣的,只是內部的細節不同,代碼是可以複用的。如果我們又要進行別墅的建造,建造過程我們又要重新寫一遍,而且很容易漏寫步驟。所以讓我們使用建造者模式改進。
使用建造者模式改進
/**
* House
*/
public class House {
private Integer length;
private Integer width;
private Integer high;
public Integer getLength() {
return length;
}
public void setLength(Integer length) {
this.length = length;
}
public Integer getWidth() {
return width;
}
public void setWidth(Integer width) {
this.width = width;
}
public Integer getHigh() {
return high;
}
public void setHigh(Integer high) {
this.high = high;
}
@Override
public String toString() {
return "House{" +
"length=" + length +
", width=" + width +
", high=" + high +
'}';
}
}
/**
* Builder
*/
public interface Builder {
void buildPartA();
void buildPartB();
Product getResult();
}
/**
* 普通房子建造者
*/
public class CommonHouseBuilder implements HouseBuilder {
private House house = new House();
@Override
public void buildHigh() {
house.setHigh(5);
}
@Override
public void buildWidth() {
house.setWidth(20);
}
@Override
public void buildLength() {
house.setLength(50);
}
@Override
public House getResult() {
return house;
}
}
/**
* 高房子建造者
*/
public class HighHouseBuilder implements HouseBuilder {
private House house = new House();
@Override
public void buildHigh() {
house.setHigh(6);
}
@Override
public void buildWidth() {
house.setWidth(30);
}
@Override
public void buildLength() {
house.setLength(60);
}
@Override
public House getResult() {
return house;
}
}
/**
* HouseDirector
*/
public class HouseDirector {
public void buildHouse(HouseBuilder houseBuilder) {
houseBuilder.buildHigh();
houseBuilder.buildLength();
houseBuilder.buildWidth();
}
}
/**
* Main
*/
public class Main {
public static void main(String[] args) {
HouseDirector houseDirector = new HouseDirector();
// 普通房子
CommonHouseBuilder commonHouseBuilder = new CommonHouseBuilder();
houseDirector.buildHouse(commonHouseBuilder);
House commonHouse = commonHouseBuilder.getResult();
System.out.println(commonHouse.toString());
// 高房子
HighHouseBuilder highHouseBuilder = new HighHouseBuilder();
houseDirector.buildHouse(highHouseBuilder);
House highHouse = highHouseBuilder.getResult();
System.out.println(highHouse.toString());
}
}
小結
建造者模式,主要用於創建一些複雜的對象,這些對象內部構建間的建造順序通常是穩定的,但對象內部的構建通常面臨複雜的變化。而建造者模式的好處就是使得建造代碼與表示代碼分離,由於建造者隱藏了該產品的構建過程,所以如果要改變一個產品內部的表示,只需再定義一個具體的建造者就可以了。
最後,建造者模式是逐步建造產品的,所以建造者的 Builder 類裏的那些建造方法必須是足夠普遍的,以便爲各類型的具體建造者構造。如果產品的差異性較大,就不適合使用建造者模式。