歡迎收看俗到掉渣的《小Y講堂》節目,大家好,我是小Y,一個集性感毛髮與才華於一身的程式猿!近日收到《魂鬥羅.歸來》中的肌肉男比爾·雷澤的投訴,說要投訴小Y最近冷落他,太久沒有讓他上節目show muscle。沒辦法,為了滿足這個悶騷的老男人,小Y把這次的主題設定為如果比爾是程式設計師,會怎麼用建造者模式來實現關卡武器裝配。oh,my God,很難想象戰鬥狂人叼著雪茄在死命敲程式碼的情形(一陣惡寒啊),得趕緊來幅小Y牌“止吐”圖來鎮鎮。
一、初出茅廬的比爾·雷澤
比爾最近迷上了程式設計,剛學到點三腳貓功夫就吵著要寫段程式碼為自己代言,要把自己不同的形象展現出來,比爾寫了以下程式碼:
①角色的基配
public class Character {
//赤裸裸的比爾雷澤,出戰前需要做充能、裝備主武器以及副武器
private Energy energy;
private MainWeapon mainWeapon;
private ViceWeapon viceWeapon;
public Character(Energy energy, MainWeapon mainWeapon, ViceWeapon viceWeapon) {
this.energy = energy;
this.mainWeapon = mainWeapon;
this.viceWeapon = viceWeapon;
}
@Override
public String toString() {
return energy.getEnergy()+mainWeapon.getMainWeapon()+viceWeapon.getViceWeapon();
}
}
複製程式碼
②出戰前基配型別(充能、選擇主武器以及副武器)
//充能
public abstract class Energy {
public abstract String getEnergy();
}
//主武器
public abstract class MainWeapon {
public abstract String getMainWeapon();
}
//副武器
public abstract class ViceWeapon {
public abstract String getViceWeapon();
}
複製程式碼
③1VS1的武器裝配
//1VS1的充能
public class OneVsOneEnergy extends Energy{
@Override
public String getEnergy() {
return "充能完成。";
}
}
//1VS1的主武器裝配
public class OneVsOneMainWeapon extends MainWeapon{
@Override
public String getMainWeapon() {
return "主武器:黃金加特林。";
}
}
//1VS1的副武器裝配
public class OneVsOneViceWeapon extends ViceWeapon{
@Override
public String getViceWeapon() {
return "副武器:集速手雷。";
}
}
複製程式碼
④3VS3的武器裝配
//3VS3的充能
public class ThreeVsThreeEnergy extends Energy{
@Override
public String getEnergy() {
return "充能完成。";
}
}
//3VS3的主武器裝配
public class ThreeVsThreeMainWeapon extends MainWeapon{
@Override
public String getMainWeapon() {
return "主武器:突擊步槍。";
}
}
//3VS3的副武器裝配
public class ThreeVsThreeViceWeapon extends ViceWeapon{
@Override
public String getViceWeapon() {
return "副武器:等離子噴射器。";
}
}
複製程式碼
⑤Client實現
public class Client {
public static void main(String[] args){
//1VS1下的比爾
Character OneVsOneOfBill=new Character(new OneVsOneEnergy(),new OneVsOneMainWeapon(),new OneVsOneViceWeapon());
System.out.println(OneVsOneOfBill);
//3VS3下的比爾
Character threeVThreeOfBill=new Character(new ThreeVsThreeEnergy(),new ThreeVsThreeMainWeapon(),new ThreeVsThreeViceWeapon());
System.out.println(threeVThreeOfBill);
}
}
複製程式碼
輸出結果
充能完成。主武器:黃金加特林。副武器:集速手雷。
充能完成。主武器:突擊步槍。副武器:等離子噴射器。
複製程式碼
對於一個剛學習程式設計的比爾來說,撇開設計模式來說,能夠寫出這樣的程式碼,小Y都是佩服得不要不要的了,但是為了唬住這個沒長全毛的比爾,小Y毅然搬出了設計模式,對比爾進行了義正言辭的批評教育:
- 隨著等級的越來越高,面對的關卡種類就會越來越多,這也意味著不同的關卡的主副武器的搭配的種類就會越來越多,況且這個例子只是一個簡單的傳參,如果傳參複雜點還按照這種傳參的方式進行會很容易搞混,出現搭配不對的情況。
- 產品的內部組成暴露給客戶端,封裝性差。
為了防止比爾反駁,小Y立馬丟擲建造者模式。
二、基本概念
1.定義
將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。
2.理解
就是把一個產品(物件)表示(展示)和構建(建立)過程分離開來,這樣產品的構建流程相同卻可以有不同的產品表示。
3.為何使用建造者模式
- 是為了將構建複雜物件的過程和它的部件解耦。
- 建造者模式的封裝性很好。使用建造者模式可以有效的封裝變化。
4.應用場景
- 同一個建立過程需要有不同的內部表象的產品物件。
- 建立複雜物件的演算法獨立於組成物件的部件。
5.角色介紹
-
Director導演類
負責呼叫適當的建造者來組建產品,導演類一般不與產品類發生依賴關係,與導演類直接互動的是建造者類。 -
Builder抽象建造者
規範產品的組建,一般是由子類實現。 -
ConcreteBuilder具體建造者
實現抽象類的所有未實現的方法,具體來說一般是兩項任務:組建產品;返回組建好的產品。。 -
Product產品類
由一系列部件組成,一般是一個較為複雜的物件,也就是說建立物件的過程比較複雜,一般會有比較多的程式碼量。 -
建造模式分成兩個很重要的部分:
一個部分是Builder介面,這裡是定義瞭如何構建各個部件,也就是知道每個部件功能如何實現,以及如何裝配這些部件到產品中去;另外一個部分是Director,Director是知道如何組合來構建產品,也就是說Director負責整體的構建演算法,而且通常是分步驟地來執行。
三、案列實現
經過小Y孜孜不倦的教誨,比爾·雷澤總算是領悟了建造者模式的精髓,決定了重新修改了修改一下上面的程式碼,經過整理得到:
1.UML清單
2.程式碼實現
①修改後角色的基配
public class Character {
//赤裸裸的比爾雷澤,出戰前需要做充能、裝備主武器以及副武器
private Energy energy;
private MainWeapon mainWeapon;
private ViceWeapon viceWeapon;
public Energy getEnergy() {
return energy;
}
public void setEnergy(Energy energy) {
this.energy = energy;
}
public MainWeapon getMainWeapon() {
return mainWeapon;
}
public void setMainWeapon(MainWeapon mainWeapon) {
this.mainWeapon = mainWeapon;
}
public ViceWeapon getViceWeapon() {
return viceWeapon;
}
public void setViceWeapon(ViceWeapon viceWeapon) {
this.viceWeapon = viceWeapon;
}
@Override
public String toString() {
return energy.getEnergy()+mainWeapon.getMainWeapon()+viceWeapon.getViceWeapon();
}
}
複製程式碼
②角色建造抽象類
public interface CharacterBuilder {
void makeEnergy();
void makeMainWeapon();
void makeViceWeapon();
public Character build();
}
複製程式碼
③1VS1具體建造者
public class OneVsOneBulider implements CharacterBuilder {
private Character character;
public OneVsOneBulider() {
this.character = new Character();
}
@Override
public void makeEnergy() {
character.setEnergy(new OneVsOneEnergy());
}
@Override
public void makeMainWeapon() {
character.setMainWeapon(new OneVsOneMainWeapon());
}
@Override
public void makeViceWeapon() {
character.setViceWeapon(new OneVsOneViceWeapon());
}
@Override
public Character build() {
return character;
}
}
複製程式碼
④3VS3具體建造者
public class ThreeVsThreeBulider implements CharacterBuilder {
private Character character;
public ThreeVsThreeBulider() {
character = new Character();
}
@Override
public void makeEnergy() {
character.setEnergy(new ThreeVsThreeEnergy());
}
@Override
public void makeMainWeapon() {
character.setMainWeapon(new ThreeVsThreeMainWeapon());
}
@Override
public void makeViceWeapon() {
character.setViceWeapon(new ThreeVsThreeViceWeapon());
}
@Override
public Character build() {
return character;
}
}
複製程式碼
⑤Director導演類
public class CharacterDirector {
private CharacterBuilder characterBuilder;
public CharacterDirector(CharacterBuilder characterBuilder) {
this.characterBuilder = characterBuilder;
}
public Character createCharacter(){
characterBuilder.makeEnergy();
characterBuilder.makeMainWeapon();
characterBuilder.makeViceWeapon();
return characterBuilder.build();
}
}
複製程式碼
⑥Client實現
public class Client {
public static void main(String[] args){
//1VS1下的比爾
CharacterBuilder oneVsOneBulider=new OneVsOneBulider();
CharacterDirector characterDirector=new CharacterDirector(oneVsOneBulider);
System.out.println(characterDirector.createCharacter());
//3VS3下的比爾
CharacterBuilder threeVsThreeBulider=new ThreeVsThreeBulider();
characterDirector=new CharacterDirector(threeVsThreeBulider);
System.out.println(characterDirector.createCharacter());
}
}
複製程式碼
輸出結果
充能完成。主武器:黃金加特林。副武器:集速手雷。
充能完成。主武器:突擊步槍。副武器:等離子噴射器
複製程式碼
四、優缺點
1.優點
-
封裝性,使用建造者模式可以使客戶端不必知道產品內部組成的細節,如例子中我們就不需要關心每一個具體的模型內部是如何實現。
-
建造者獨立,容易擴充套件。OneVsOneBulider和ThreeVsThreeBulider是相互獨立的,對系統的擴充套件非常有利。
-
便於控制細節風險。由於具體的建造者是獨立的,因此可以對建造過程逐步細化,而不對其他的模組產生任何影響。
-
增加新的具體建造者無須修改原有類庫的程式碼,指揮者類針對抽象建造者類程式設計,系統擴充套件方便,符合“開閉原則”。
2.缺點
-
建造者模式所建立的產品一般具有較多的共同點,其組成部分相似,如果產品之間的差異性很大,則不適合使用建造者模式,因此其使用範圍受到一定的限制。
-
如果產品的內部變化複雜,可能會導致需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大。
五、總結
建造者模式關注的是零件型別和裝配工藝(順序),這是它與工廠方法模式最大不同的地方,雖然同為建立類模式,但是注重點不同。下一篇就是工廠方法模式,有興趣的可以繼續留意。
節目到了尾聲了,讓我們用熱烈的掌聲感謝重量級嘉賓比爾雷澤,好走不送。