建造者模式

业务场景

在业务代码中构造了一个类,里面有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);
    }

image-20211011165554113

不同的家具、房间构成了不同的房子,如果将来业务扩展改动影响也不大

总结

一些基本东西不会变,而其组合经常变化的时候,就适合用建造者模式,特别是很多字段,很多种组合的时候,这种设计结构模型可以把重复的内容抽象

工厂模式和建造者模式的区别

工厂模式是用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象。建造者模式是用来创建一种类型的复杂对 象,通过设置不同的可选参数,“定制化”地创建不同的对象。

原文地址:https://www.cnblogs.com/cg-ww/p/15394145.html