天天看點

建造者模式

業務場景

在業務代碼中構造了一個類,裡面有7個字段,需要給構造方法傳7個值

public class Home {
    //門
    private String Door;
    //椅子
    private String Chair;
    //廚房
    private String Kitchen;
    //馬桶
    private String Toilet;
    //浴室
    private String Bathroom;
    //書房
    private String Study;
    //遊泳池
    private  String SwimmingPoor;

    public void setDoor(String door) {
        Door = door;
    }

    public void setChair(String chair) {
        Chair = chair;
    }

    public void setKitchen(String kitchen) {
        Kitchen = kitchen;
    }

    public void setToilet(String toilet) {
        Toilet = toilet;
    }

    public void setBathroom(String bathroom) {
        Bathroom = bathroom;
    }

    public void setStudy(String study) {
        Study = study;
    }

    public void setSwimmingPoor(String swimmingPoor) {
        SwimmingPoor = swimmingPoor;
    }
    public Home(String door, String chair, String kitchen, String toilet, String bathroom, String study, String swimmingPoor) {
        Door = door;
        Chair = chair;
        Kitchen = kitchen;
        Toilet = toilet;
        Bathroom = bathroom;
        Study = study;
        SwimmingPoor = swimmingPoor;
    }
    public Home() {
    }
}
           

因為需要建房子,當時我們的類後面經過擴充發展到了15個字段,甚至更多

private String Door;//門
private String Chair;  //椅子
private String Kitchen;  //廚房
private String Toilet;  //馬桶
private String Bathroom;   //浴室
private String Study;    //書房
private  String SwimmingPoor;    //遊泳池
.........
           

那繼續沿用現在的設計思路,構造函數的參數清單會變得很長,代碼在可讀性和易用性上都會變差。在使用構造函數的時候,我們就容易搞錯各參數的順序,傳遞進錯誤的參數值,導緻非常隐蔽的 bug。

Home home=new Home("鐵門","搖搖椅","廚房","","",......)
           

于是乎可能想到使用set方法來解決,可以選擇填寫或者不填寫

Home home=new Home();
        home.setBathroom("玻璃浴室");
        home.setChair("木椅子");
        home.setDoor("防盜門");
        home.setStudy("書房");
        home.setToilet("");
        home.set....
           

但問題又來了,如果我們的構造方法需要進行擴充,比如建有的類型的房子,有的參數不需要使用了,又編寫新的構造方法,一個參數依賴另外兩個參數,比如我設定了房間的大小,長寬這兩個屬性是互相依賴的。

public Home(String door, String chair, String kitchen,String width,String height)
    {
        Door = door;
        Chair = chair;
        Kitchen = kitchen;
        Width=width;
        Height=height;
    }
           

這樣很好,可是如果我們參數就是随意更改和搭配的,那麼每次都需要我重新編寫構造參數,這樣還将細節對外暴露了。單純用構造函數或者set方法無法做到對參數進行限制,對象可能還存在空或者無效。

建造者模式重構

例如上面,有很多參數需要我們去搭配修改,用來建立不同的對象方法

就像建房子,我們不需要去建,隻需要把我們的需求告訴建造者,讓它去建立,最後我隻管得到這個房子去驗收。

建造者接口

public interface IHome {
         IHome Door(String door);//桌子
         IHome Chair(String chair);  //椅子
         IHome Kitchen(String kitchen);  //廚房
         IHome Toilet(String toilet);  //馬桶
         IHome Bathroom(String bathroom);   //浴室
         String getDetail();//詳細資訊
}
           

具體實作的建造者

public class HomeBuilder implements IHome {
    Home home=new Home();

    List<String> list=new ArrayList<>();
    @Override
    public IHome Door(String door) {
        home.setDoor(door);
        list.add(door);
        return  this;
    }

    @Override
    public IHome Chair(String chair) {
        home.setChair(chair);
        list.add(chair);
        return  this;
    }

    @Override
    public IHome Kitchen(String  kitchen) {
        home.setKitchen(kitchen);
        list.add(kitchen);
        return  this;
    }

    @Override
    public IHome Toilet(String  toilet) {
        home.setToilet(toilet);
        list.add(toilet);
        return  this;
    }

    @Override
    public IHome Bathroom(String  bathroom) {
        home.setBathroom(bathroom);
        list.add(bathroom);
        return  this;
    }

    @Override
    public String getDetail() {
        StringBuilder detail = new StringBuilder();
        for (String s : list) {
            detail.append(s+" ");
        }
        return  detail.toString();
    }
}
           

建造者方法

public class Build {
    //普通出租房
    public  IHome leveZero() {
        return  new HomeBuilder().Chair("塑膠椅").Door("塑膠門").Kitchen("小廚房");
    }

    //紅木家庭房子
    public  IHome leveOne() {
        return  new HomeBuilder().Chair("紅木椅").Bathroom("浴室").Door("紅木門");
    }

    //歐式家庭房子
    public  IHome leveTwo() {
        return  new HomeBuilder().Chair("北歐ins椅").Bathroom("露天浴室").Door("北歐ins門").Kitchen("北歐廚房");
    }
}
           

測試驗證

public void  test()
    {
        Build build=new Build();
        String detail = build.leveOne().getDetail();
        System.out.println(detail);

        String detail2 = build.leveZero().getDetail();
        System.out.println(detail2);
    }
           
建造者模式

不同的家具、房間構成了不同的房子,如果将來業務擴充改動影響也不大

總結

一些基本東西不會變,而其組合經常變化的時候,就适合用建造者模式,特别是很多字段,很多種組合的時候,這種設計結構模型可以把重複的内容抽象

工廠模式和建造者模式的差別

工廠模式是用來建立不同但是相關類型的對象(繼承同一父類或者接口的一組子類),由給定的參數來決定建立哪種類型的對象。建造者模式是用來建立一種類型的複雜對 象,通過設定不同的可選參數,“定制化”地建立不同的對象。