Java設計模式-建造者(Builder)模式
阿新 • • 發佈:2018-12-09
最近在看Mybatis
的原始碼, 在閱讀解析 XML
配置檔案的過程中, 發現使用到了建造者(Builder)模式。 因此, 打算重溫一下該設計模式。
由來
假設我們需要畫一個小人, 我們可能會有以下的建構函式定義:
public Person(HeadType headType, HairType hairType, HairColor hairColor, FaceType faceType, BodyType bodyType, ArmType amrType, LegType legTyype) {
}
看到這麼一個建構函式, 估計我們自己以後回來看的時候都懵了, 這麼多引數, 導致我們後續的維護也很麻煩。
而構造模式就可以解決此類的問題。
使用
目標是畫一個小人
1. 定義抽象 Builder
先定義抽象的PersonBuilder
。 該類定義了畫小人需要的步驟, 這樣每個通過PersonBuilder
產生的物件本質上就都是一樣的了, 只不過個性上可以不一樣。
abstract class PersonBuilder { protected Graphics graphics; public PersonBuilder(Graphics graphics) { this.graphics = graphics; } public abstract void buildHead(); public abstract void buildBody(); public abstract void buildArmLeft(); public abstract void buildArmRight(); public abstract void buildLegLeft(); public abstract void buildLegRight(); }
2. 定義具體 Builder
類
在定義一個具體的實現類PersonFatBuilder
。 該類繼承PersonBuilder
, 並實現了抽象方法。
public class PersonFatBuilder extends PersonBuilder { public PersonFatBuilder(Graphics graphics) { super(graphics); } @Override public void buildHead() { graphics.drawOval(50, 20, 30, 30); graphics.drawArc(50, 30, 10, 5, 45, 135); graphics.drawArc(70, 30, 10, 5, 45, 135); graphics.drawArc(60, 35, 10, 5, 200, 135); } @Override public void buildBody() { graphics.drawRect(55, 50, 20, 50); } @Override public void buildArmLeft() { graphics.drawLine(55, 50, 40, 100); } @Override public void buildArmRight() { graphics.drawLine(75, 50, 90, 100); } @Override public void buildLegLeft() { graphics.drawLine(55, 100, 45, 150); } @Override public void buildLegRight() { graphics.drawLine(75, 100, 85, 150); } }
3. 定義具體 Director
類
該類負責具體的建造過程, 對建成什麼樣不關心。
public class PersonDirector {
private PersonBuilder personBuilder;
public PersonDirector(PersonBuilder personBuilder) {
this.personBuilder = personBuilder;
}
public void drawPerson() {
personBuilder.buildHead();
personBuilder.buildBody();
personBuilder.buildArmLeft();
personBuilder.buildArmRight();
personBuilder.buildLegLeft();
personBuilder.buildLegRight();
}
}
4. 測試
建立一個視窗,將小人畫出來。
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
// 建立視窗物件
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setTitle("畫人");
frame.setSize(250, 300);
// 設定視窗關閉按鈕的預設操作(點選關閉時退出程序)
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// 把視窗位置設定到螢幕的中心
frame.setLocationRelativeTo(null);
frame.setContentPane(new JPanel(){
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
PersonThinBuilder thinBuilder = new PersonThinBuilder(g);
PersonDirector director = new PersonDirector(thinBuilder);
director.drawPerson();
}
});
}
});
}
結果如下:
定義
文字定義
將複雜物件的構建與它的表示分離, 使得同樣的構建過程可以建立不同的表示。
換句話解釋, 允許你建立不同種類的物件, 同時又能避免對建構函式的汙染。當物件有多種型別時, 該模式非常有用。 或者在建立物件時涉及到很多的步驟。
結構圖
引用《大話設計模式》的一個圖
抽象類Builder
:為建立Product
物件而抽象的介面。
繼承類ConcreateBuilder
:具體的建造者, 構造和裝配各個部件。
具體產品類Product
:我們需要建造的物件。
Director
: 用來建立產品的, 其內部有Builder
型別的成員變數。
優點
Director
不需要知道Product
的內部細節, 它只提供需要的資訊給建設者, 由具體的建造者ConcreateBuilder
處理從而完成產品的構造。- 建造者模式將複雜的產品建立過程分散到了不同的物件中, 從而實現對產品建立過程更精確的控制, 建立過程更加清晰。
- 每個具體的建造者都可以創建出完整的產品物件, 而且是相互獨立的。 因此, 呼叫端可以通過不同的具體建造者就可以得到不同的物件。當有新的產品出現時, 不需要改變原有程式碼, 只需要新增一個建造者即可。
舉例
現在如果我們想建造一個胖小人,有五官的。那我們只需要新增一個PersonFatBuilder
類就可以了, 不需要改原有程式碼。
public class PersonFatBuilder extends PersonBuilder {
public PersonFatBuilder(Graphics graphics) {
super(graphics);
}
@Override
public void buildHead() {
graphics.drawOval(50, 20, 30, 30);
graphics.drawArc(50, 30, 10, 5, 45, 135);
graphics.drawArc(70, 30, 10, 5, 45, 135);
graphics.drawArc(60, 35, 10, 5, 200, 135);
}
@Override
public void buildBody() {
graphics.drawRect(55, 50, 20, 50);
}
@Override
public void buildArmLeft() {
graphics.drawLine(55, 50, 40, 100);
}
@Override
public void buildArmRight() {
graphics.drawLine(75, 50, 90, 100);
}
@Override
public void buildLegLeft() {
graphics.drawLine(55, 100, 45, 150);
}
@Override
public void buildLegRight() {
graphics.drawLine(75, 100, 85, 150);
}
}
結果: