1. 程式人生 > >設計模式的藝術 建立型模式之建造者模式

設計模式的藝術 建立型模式之建造者模式

不懂使用為學過,說出用途,繪製結構為了解,不會靈活使用基本等於沒學。

前言

沒有人想買汽車的時候只會單獨買一個輪胎或者一個方向盤,大家買的都是組裝好的一輛完整的汽車,如何將這些部件組裝成一個完整的汽車並返回給客戶,這就是建造者模式需要解決的問題。建造者模式又被稱之為生成器模式,它是一種較為複雜、使用頻率也相對其他建立型模式較低的一種模式,建造者模式為客戶端返回的不是一個簡單的產品,而是一個由多個部件組成的複雜產品

什麼是建造者模式 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());

    }
}