建造者模式(Builder Pattern)屬於建立型模式中的一種,在建立比較複雜的對象,或者對象包含多個組成部分時比較有用,用於將對象的建立過程與使用分離,隔離具體的建立細節,方便之後的擴展。它的使用場景包括:設計模式
本文將以一個具體的例子做爲引子,經過對比的形式講解建造者模式的優勢,最後引入定義和類圖。ide
這裏以作菜爲例子,一般作菜的步驟包括:放油,放蔥薑蒜,加肉,翻炒,加鹽,繼續翻炒,裝盤,那麼作一份豆角炒肉代碼能夠這樣寫:ui
public class SimpleCook { public static void main(String[] args) { SimpleCook cook = new SimpleCook(); cook.cookmeatWithBeans(); } public void cookmeatWithBeans(){ System.out.println("熱鍋下油。。。"); System.out.println("加肉。。。"); System.out.println("加入蔥薑蒜。。。"); System.out.println("放入豆角。。。"); System.out.println("翻炒均勻。。。"); System.out.println("加鹽,繼續翻炒。。。"); System.out.println("出鍋。。。"); } }
OK,一盤香噴噴的豆角炒肉就作好了。不過,上面的代碼還有一些問題:①代碼將每一個步驟一筆帶過,實際上每一步都會有許多細節,好比第一步下油,何時倒油,倒多少合適?若是把這些詳細步驟所有寫在一塊兒,各個步驟之間不只耦合嚴重,並且代碼還會顯得雜亂,一旦某個步驟須要改善,整個方法都受影響;②擴展性問題,若是我想換個藕丁炒肉,那就須要新添加一個方法,沒有擴展性。並且咱們會發現豆角炒肉和藕丁炒肉全部的步驟都同樣,只是把「放入豆角」改爲了「放入藕丁」,隨着類型菜品的增多,系統會充斥大量的冗餘代碼。this
所以,這裏須要將每一個步驟單獨提出來做爲一個方法,炒菜的步驟修改以後以下:spa
public class SimpleCook { public static void main(String[] args) { SimpleCook cook = new SimpleCook(); cook.cookMeatWithBeansBetterWay(); } public void cookMeatWithBeansBetterWay(){ addOil(); addMeat(); addIngredients(); addDish(); cookForAWhile(); addSalt(); finish(); } private void finish() { System.out.println("出鍋。。。"); } private void addSalt() { System.out.println("加鹽,繼續翻炒。。。"); } private void cookForAWhile() { System.out.println("翻炒均勻。。。"); } private void addDish() { System.out.println("放入豆角。。。"); } private void addIngredients() { System.out.println("加入蔥薑蒜。。。"); } private void addMeat() { System.out.println("加肉。。。"); } private void addOil() { System.out.println("熱鍋下油。。。"); } }
因爲不少菜品都遵循相似的步驟,只是具體實現不同,那麼就能夠抽象出一個父類,而後具體的步驟交給子類去實現,對於其中共同的部分,能夠在抽象父類中提供默認實現:設計
public abstract class Builder { public abstract void addOil(); public abstract void addMeat(); public abstract void addIngredients(); public abstract void addDish(); public void cookForAWhile(){ System.out.println("翻炒均勻。。。"); } public abstract void addSalt(); public void finish(){ System.out.println("出鍋。。。"); } }
抽象父類提供了兩個方法的默認實現,其餘的交給子類去處理,下面是藕丁炒肉子類的實現,豆角炒肉與此相似:3d
public class MeatWithLotusRootBuilder extends Builder{ @Override public void addOil() { System.out.println("熱鍋下油。。。"); } @Override public void addMeat() { System.out.println("加肉。。。"); } @Override public void addIngredients() { System.out.println("加入蔥薑蒜。。。"); } @Override public void addDish() { System.out.println("放入藕丁。。。"); } @Override public void addSalt() { System.out.println("加鹽,繼續翻炒。。。"); } }
如今,就能夠按照開始規定的步驟炒菜了,這裏,咱們將炒菜的流程放在Director中,由該類管理具體的步驟順序:code
public class Director { Builder builder; public Director(Builder builder){ this.builder = builder; } public void cook(){ builder.addOil(); builder.addIngredients(); builder.addMeat(); builder.addDish(); builder.cookForAWhile(); builder.addSalt(); builder.finish(); } }
當咱們須要點餐時,只須要告訴Director菜品的名字就能夠了,菜就會按照流程作出來:對象
// 客戶端代碼 public class BuilderCook { public static void main(String[] args) { Builder builder = new MeatWithLotusRootBuilder(); Director director = new Director(builder); director.cook(); } }
輸出爲:blog
熱鍋下油。。。
加入蔥薑蒜。。。
加肉。。。
放入藕丁。。。
翻炒均勻。。。
加鹽,繼續翻炒。。。
出鍋。。。
相比最開始的炒菜方法,改進以後增長了Director、Builder、Builder子類,Director類規定了建立對象的順序,Builder抽象了炒菜的通常步驟,Builder子類則對應每種菜品的具體實現。
根據上面的代碼,總結出建造者模式的類結構以下:
其通常定義爲:
建造者模式:將一個複雜對象的構建與它的表示相分離,使得一樣的構建過程能夠建立不一樣的表示。
工做中,建造者模式更常見的使用場景是對象要設置的參數過多的狀況,例如,將人抽象爲一個Person類,建立的時候須要傳遞許多信息,可使用各類setter方法,可是Builder模式可以讓這種寫法更優雅,代碼以下:
public class Person { String name; int age; double height; double weight; String sex; //省略其餘字段 public static void main(String[] args) { Person person = new Builder().name("zhang san") .age(20).height(174) .weight(130) .sex("male") .build(); } public Person(Builder builder){ this.age = builder.age; this.height = builder.height; this.weight = builder.weight; this.name = builder.name; this.sex = builder.sex; } public static class Builder{ String name; int age; double height; double weight; String sex; public Builder age(int age){ this.age = age; return this; } public Builder height(double height){ this.height = height; return this; } public Builder weight(double weight){ this.weight = weight; return this; } public Builder name(String name){ this.name = name; return this; } public Builder sex(String sex){ this.sex = sex; return this; } public Person build(){ return new Person(this); } } }
<<大話設計模式>>