設計模式的藝術 建立型模式之建造者模式
不懂使用為學過,說出用途,繪製結構為了解,不會靈活使用基本等於沒學。
前言
沒有人想買汽車的時候只會單獨買一個輪胎或者一個方向盤,大家買的都是組裝好的一輛完整的汽車,如何將這些部件組裝成一個完整的汽車並返回給客戶,這就是建造者模式需要解決的問題。建造者模式又被稱之為生成器模式,它是一種較為複雜、使用頻率也相對其他建立型模式較低的一種模式,建造者模式為客戶端返回的不是一個簡單的產品,而是一個由多個部件組成的複雜產品
什麼是建造者模式 Builder Pattern
將一個複雜的物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。建造者模式是一個物件建立型模式
建造者模式的優點
(1)、在建造者模式中,客戶端不必要知道產品內部組成的細節,將產品本身與產品的建立過程解耦,使得相同的建立過程可以建立不同的產品物件
(2)、每個具體的建造者都相對獨立,而與其他具體的建造者無關,因此可以很方便地替換具體建造者或增加新的具體建造者,使用者使用不同的具體建造者即可得到不同的產品物件。由於指揮者類針對抽象建造者程式設計,增加新的具體建造者無須修改原有類庫的程式碼,系統擴充套件方便,符合開閉原則。
(3)、我們可以更加精確的控制產品的建立過程。將複雜產品的建立步驟分解在不同的方法中,使得建立過程更加清晰,也更方便使用程式來控制建立過程。
建造者模式的缺點
(1)、建造者模式一般所建立的產品都具有比較多的共同點,其組成部分相似,如果產品之間的差異性很大,例如很多組成部分都不相同,就不適合使用建立者模式,因此其受用範圍是有一定的限制
(2)、如果產品內部的結構複雜多變,可能會需要定義很多具體建造者類來實現變化,這樣就很導致系統變得很龐大,增加系統的理解難度和執行成本。
建造者模式的使用場景
(1)、需要生成的產品物件有複雜的內部結構,這些產品物件通常包含多個成員變數。
(2)、需要生成的產品物件的屬性相互依賴,需要制定其生成順序
(3)、物件的建立過程獨立於建立該物件的類。在建造者模式中通過引入指揮類,將建立過程封裝在指揮者類中,而不再建造者類和客戶類中。
(4)、隔離複雜物件的建立和使用,並使得相同的建立過程可以建立不同的產品。
建造者模式的具體實現
一、目錄結構
二、複雜產品類
package com.company; //Actor角色類,複雜產品,考慮到程式碼可讀性,只列出部分成員變數 public class Actor { private String type; //角色型別 private String sex; //性別 private String face; //臉型 private String costume; //服裝 private String hairstyle; //髮型 public String getType() { return type; } public void setType(String type) { this.type = type; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getFace() { return face; } public void setFace(String face) { this.face = face; } public String getCostume() { return costume; } public void setCostume(String costume) { this.costume = costume; } public String getHairstyle() { return hairstyle; } public void setHairstyle(String hairstyle) { this.hairstyle = hairstyle; } }
三、角色建造者器
package com.company; //角色建造器:抽象建造者 public abstract class ActorBuilder { protected Actor actor=new Actor(); public abstract void buildType(); public abstract void buildSex(); public abstract void buildFace(); public abstract void buildCostume(); public abstract void buildHairstyle(); //鉤子方法,對複雜產品的構建進行精準的控制 public boolean isBareheaded(){ return false; } //工廠方法,返回一個完整的角色物件 public Actor createActor(){ return actor; } }
四、構建物件
package com.company; //遊戲角色建立控制器:指揮者 public class ActorController { //逐步構建複雜產品物件 public Actor construct(ActorBuilder actorBuilder){ Actor actor; actorBuilder.buildCostume(); actorBuilder.buildFace(); actorBuilder.buildSex(); actorBuilder.buildType(); //通過鉤子方法來控制產品的構建 if(!actorBuilder.isBareheaded()){ //惡魔類中覆蓋了父類的方法,返回true因為惡魔沒有頭髮 actorBuilder.buildHairstyle(); } actor=actorBuilder.createActor(); return actor; } }
五、具體的建造者類
package com.company; //天使類角色,具體建立者 public class AngleBuilder extends ActorBuilder { @Override public void buildType() { actor.setType("天使"); } @Override public void buildSex() { actor.setSex("女"); } @Override public void buildFace() { actor.setFace("漂亮"); } @Override public void buildCostume() { actor.setCostume("白裙"); } @Override public void buildHairstyle() { actor.setHairstyle("披肩長髮"); } }
六、輔助類
package com.company; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.File; public class XMLUtil { //從XML檔案中提取一個具體類名名稱,並返回一個例項物件 public static Object getBean(){ //建立文件物件 try { DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance(); DocumentBuilder builder=factory.newDocumentBuilder(); Document doc=builder.parse(new File(XMLUtil.class.getClassLoader().getResource("").getPath()+"config.xml")); //獲取包含類名的文字節點 NodeList nodeList=doc.getElementsByTagName("className"); Node node=nodeList.item(0).getFirstChild(); String name=node.getNodeValue(); //通過類名生成例項物件並將其返回 /*System.out.println(name);*/ Class c=Class.forName(name); Object obj=c.newInstance(); return obj; } catch (Exception e) { e.printStackTrace(); return null; } } }
七、配置檔案(config.xml)
<?xml version="1.0" encoding="UTF-8" ?> <config> <className>com.company.AngleBuilder</className> </config>
八、測試檔案
package com.company; public class Main { //編寫測試程式碼 public static void main(String[] args) { // write your code here ActorBuilder ac; //針對抽象建造者程式設計 ac=(ActorBuilder)XMLUtil.getBean(); //反射生成具體建造者物件 ActorController ab=new ActorController(); Actor actor; actor=ab.construct(ac); //通過指揮者建立完整的建造者物件 String type=actor.getType(); System.out.println(type+"的外觀"); System.out.println("性別"+actor.getSex()); System.out.println("面容"+actor.getFace()); System.out.println("服裝"+actor.getCostume()); System.out.println("髮型"+actor.getHairstyle()); } }