文章出處

簡介

建造者模式(Builder),將一個復雜對象的表示和它的構建分離,這樣同樣的構造過程可以創建出不同的對象狀態。

類圖

下面的Product是要創建的對象的目標類型,產品。

  • Builder
    創建一個Product對象涉及的操作的抽象接口,定義了Product各個部分的創建方法。

  • Director
    使用Builder來構建Product,控制構建過程。

  • ConcreteBuilder
    一個具體的構建者。

樣例代碼

目標類型Robot

假設要構建一個機器人Robot類型的對象:

public class Robot {
    private String head;
    private String arm;
    private String leg;
    private String body;

    // getter & setter 省略

    public String getDescription() {
        return toString();
    }

    @Override
    public String toString() {
        return "Robot{" +
                "head='" + head + '\'' +
                ", arm='" + arm + '\'' +
                ", leg='" + leg + '\'' +
                ", body='" + body + '\'' +
                '}';
    }
}

RobotBuilder

使用RobotBuilder接口(也可以是抽象類)來定義Robot各個部分的設置。

public interface RobotBuilder {
   void setArm();
   void setLeg();
   void setBody();
   void setHead();
}

具體的RobotBuilder

可以定義不同RobotBuilder子類來實現不同的Robot的構建。

BigRobotBuilder

構建一個“Big Robot”的建造器如下:

public class BigRobotBuilder implements RobotBuilder {
    private Robot mRobot;

    public BigRobotBuilder(Robot robot) {
        mRobot = robot;
    }

    @Override
    public void setArm() {
        mRobot.setArm("Big arm");
    }

    @Override
    public void setLeg() {
        mRobot.setLeg("Big leg");
    }

    @Override
    public void setBody() {
        mRobot.setBody("Big body");
    }

    @Override
    public void setHead() {
        mRobot.setHead("Big head");
    }
}

MiniRobotBuilder

構建一個“Mini Robot”的建造器如下:

public class MiniRobotBuilder implements RobotBuilder {
    private Robot mRobot;

    public MiniRobotBuilder(Robot robot) {
        mRobot = robot;
    }

    @Override
    public void setArm() {
        mRobot.setArm("Mini arm");
    }

    @Override
    public void setLeg() {
        mRobot.setLeg("Mini leg");
    }

    @Override
    public void setBody() {
        mRobot.setBody("Mini body");
    }

    @Override
    public void setHead() {
        mRobot.setHead("Mini head");
    }
}

RobotBuildDirector

控制Robot構建過程的指揮者:

public class RobotBuildDirector {
    public void buildRobot(RobotBuilder builder) {
        builder.setBody();
        builder.setArm();
        builder.setHead();
        builder.setLeg();
    }
}

如果構建過程需要嚴格順序的話,那么Director來封裝具體構建過程是很重要的。

調用代碼

創建一個具體的builder,然后執行Director.buildRobot()來完成構建:

void main() {
    Robot robot = new Robot();
    RobotBuildDirector director = new RobotBuildDirector();
    RobotBuilder builder = new BigRobotBuilder(robot);
    director.buildRobot(builder);

    // 顯示已構建的robot的詳細信息
    Log.println(robot.getDescription());
}

小結

以上的Robot案例展示了builder模式的標準形式。
實際使用中,可能沒有抽象Builder和Director控制過程這樣的需要。
而是,僅僅希望將包含很多可設置的屬性的類型的構建相關的代碼與類型本身分開。
而且,設置屬性的類往往就作為要配置的類的子類。

下面的實際案例中會說明這點。

實際案例

Diaglog

在Android開發中,AlertDialog類型的構建就使用到了Builder模式,而且是簡化了的。

AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
AlertDialog dialog = dialogBuilder.setIcon(R.drawable.ic_launcher)
        .setMessage("message")
        .setTitle("Title")
        .setNegativeButton("Cancel", null)
        .create();

內部類AlertDialog.Builder用來對AlertDialog的不同的屬性進行設置。
注意到setMessage()、setTitle()等方法都返回AlertDialog.Builder對象本身,
這樣就可以以“鏈式代碼”的形式對多個屬性進行設置。這樣的api很常見,如:

StringBuilder sb = new StringBuilder();
sb.append(1).append(2).append(2);

再如:

SharedPreferences sp = getSharedPreferences("1", MODE_PRIVATE);
sp.edit().putBoolean("1", false)
        .putInt("2", 2)
        .putLong("3", 3L)
        .remove("2")
        .apply();

可以看到,Builder對外暴露實際要使用的AlertDialog的各種屬性的設置,而且它可以提供一些默認配置。這樣使用者就無需每個屬性都去指定。
當調用者完成對AlertDialog的一些方面的定制后,執行create()返回最終的dialog對象。

其它例子

Notification也是:

Notification.Builder builder = new Notification.Builder(this);
        Notification.Action action = null;
        String category = "";
        builder.addAction(action)
                .setCategory(category)
                .setColor(0xff00ff00)
                .setNumber(10086)
                .setGroup("groupKey")
                .build();

其它一些第三方庫,或者非Android框架中也有類似Builder模式的大量運用,貴在積累和學習。

總結

可以看到,實際使用中的builder模式和標準的模式組成稍微不同。
很多已知的API中,對構建著模式的使用就是:
將一個包含很多不同屬性的對象的設置相關邏輯封裝為一個靜態內部類去完成。

(本文使用Atom編寫)


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()