建造者模式

定义

建造者模式(Builder):将一个对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用建造者模式。

实现

案例:

外卖套餐

外卖套餐里面有必点,选点,然后各个菜品可以随意组合

必点:米饭、餐具

选点:小炒肉、土豆丝、麻婆豆腐。。。

public class WaiMai {

    private String rice;
    private String chopsticks;

    private String xcr;
    private String tds;
    private String mpdf;

    public WaiMai(String rice, String chopsticks) {
        this.rice = rice;
        this.chopsticks = chopsticks;
    }

    public WaiMai(String rice, String chopsticks, String xcr) {
        this.rice = rice;
        this.chopsticks = chopsticks;
        this.xcr = xcr;
    }

    public WaiMai(String rice, String chopsticks, String xcr, String tds, String mpdf) {
        this.rice = rice;
        this.chopsticks = chopsticks;
        this.xcr = xcr;
        this.tds = tds;
        this.mpdf = mpdf;
    }
    //方式一:通过构造函数来组合
        //... 随着菜品的增多,这些组合是无限多的。那么这种构造函数也就无限多了,想想都不想写代码了。

    //方式二:除了必点的使用构造函数,其他的都是 set 方法
        // 虽然 set 相对来说,代码少了很多,但是 set 太随意了,你压根不知道这个套餐里面有没有这个菜,那么可能就会出错。
    public void setXcr(String xcr) {
        this.xcr = xcr;
    }

    public void setTds(String tds) {
        this.tds = tds;
    }

    public void setMpdf(String mpdf) {
        this.mpdf = mpdf;
    }
    
}

所以,为了解决上面两种问题,建造者模式就出现了。

实战

产品:外卖

public class WaiMai {

    private String rice;//米饭
    private String chopsticks;//筷子

    private String xcr;//小炒肉
    private String tds;//土豆丝
    private String mpdf;//麻婆豆腐

    public WaiMai(String rice, String chopsticks) {
        this.rice = rice;
        this.chopsticks = chopsticks;
    }
    
    public void setXcr(String xcr) {
        this.xcr = xcr;
    }

    public void setTds(String tds) {
        this.tds = tds;
    }

    public void setMpdf(String mpdf) {
        this.mpdf = mpdf;
    }
    
        @Override
    public String toString() {
        return "WaiMai{" +
                "rice='" + rice + '\'' +
                ", chopsticks='" + chopsticks + '\'' +
                ", xcr='" + xcr + '\'' +
                ", tds='" + tds + '\'' +
                ", mpdf='" + mpdf + '\'' +
                '}';
    }

}

Builder

定义一个接口,表明需要建造什么,得到什么

public interface WaiMaiBuilder {
    void setXcr();
    void setTds();
    void setMpdf();
    WaiMai getWaiMai();
}

ConcreteBuilder

此时还没有生产套餐,只是定义套餐(下面只是使用一个套餐A,其他套餐同理)

public class WaiMaiConcreteBuilderA implements WaiMaiBuilder {
    private  WaiMai waiMai;

    //因为这个是产品必须的,所以这里也必须有
    public WaiMaiConcreteBuilderA(String rice,String chopstick){
        waiMai = new WaiMai(rice,chopstick);
    }

    @Override
    public void setXcr() {
        waiMai.setXcr("小炒肉");
    }

    @Override
    public void setTds() {
        waiMai.setTds("土豆丝");
    }

    @Override
    public void setMpdf() {
        waiMai.setMpdf(null);
        System.out.println("套餐A没有麻婆豆腐");
    }

    @Override
    public WaiMai getWaiMai() {
        return waiMai;
    }
}

Director

真正的执行者,就像你自己在点餐的时候一样

public class Director {
    public WaiMai build(WaiMaiBuilder builder){
        builder.setMpdf();
        builder.setTds();
        builder.setXcr();
        return builder.getWaiMai();
    }
}

测试类

public class BuilderTest {
    public static void main(String[] args) {
        //必点品
        WaiMaiBuilder builderA=new WaiMaiConcreteBuilderA("米饭","筷子");
        //执行者创建产品,并不了解产品的细节
        WaiMai waiMai=new Director().build(builderA);
        System.out.println(waiMai);
    }
}

//打印结果:
套餐A没有麻婆豆腐
WaiMai{rice='米饭', chopsticks='筷子', xcr='小炒肉', tds='土豆丝', mpdf='null'}

那么到这里,一个 “标准” 的建造者模式就实现了出来,如下UML图所示:
在这里插入图片描述

简化版

//实体类
public class WaiMai {

    private String rice;
    private String chopsticks;

    private String xcr;
    private String tds;
    private String mpdf;

    public WaiMai(WaiMaiBuilder waiMaiBuilder) {
        rice = waiMaiBuilder.rice;
        chopsticks = waiMaiBuilder.chopsticks;
        xcr = waiMaiBuilder.xcr;
        tds = waiMaiBuilder.tds;
        mpdf = waiMaiBuilder.mpdf;
    }

    @Override
    public String toString() {
        return "WaiMai{" +
                "rice='" + rice + '\'' +
                ", chopsticks='" + chopsticks + '\'' +
                ", xcr='" + xcr + '\'' +
                ", tds='" + tds + '\'' +
                ", mpdf='" + mpdf + '\'' +
                '}';
    }
    
// 静态内部类
    public static class WaiMaiBuilder {
        private String rice;
        private String chopsticks;

        private String xcr;
        private String tds;
        private String mpdf;

        public WaiMaiBuilder(String rice,String chopstick) {
            this.rice=rice;
            chopsticks=chopstick;
        }

        public WaiMaiBuilder setXcr() {
            this.xcr="小炒肉";
            return this;
        }

        public WaiMaiBuilder setTds() {
            this.tds="土豆丝";
            return this;
        }

        public WaiMaiBuilder setMpdf() {
            this.mpdf="麻婆豆腐";
            return this;
        }

        public WaiMai getWaiMai() {
            return new WaiMai(this);
        }
    }
}

// 测试
public class BuilderTest {
    public static void main(String[] args) {
        WaiMai waiMai=new WaiMai.WaiMaiBuilder("米饭","筷子").setMpdf().setXcr().getWaiMai();
        System.out.println(waiMai);
    }
}

Lombok-builder

@Builder(toBuilder = true)
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class WaiMai {
    private String rice;
    private String chopsticks;

    private String xcr;
    private String tds;
    private String mpdf;

    public WaiMai(String rice, String chopsticks) {
        this.rice = rice;
        this.chopsticks = chopsticks;
    }
}

// 测试
public class BuilderTest {
    public static void main(String[] args) {
        WaiMai waiMai= new WaiMai("米饭","筷子").toBuilder().mpdf("麻婆豆腐").build();
        System.out.println(waiMai);
    }
}



WaiMai.class 文件:
public class WaiMai {
    private String rice;
    private String chopsticks;
    private String xcr;
    private String tds;
    private String mpdf;

    public WaiMai(String rice, String chopsticks) {
        this.rice = rice;
        this.chopsticks = chopsticks;
    }

    public static WaiMai.WaiMaiBuilder builder() {
        return new WaiMai.WaiMaiBuilder();
    }

    public WaiMai.WaiMaiBuilder toBuilder() {
        return (new WaiMai.WaiMaiBuilder()).rice(this.rice).chopsticks(this.chopsticks).xcr(this.xcr).tds(this.tds).mpdf(this.mpdf);
    }

    public String toString() {
        return "WaiMai(rice=" + this.rice + ", chopsticks=" + this.chopsticks + ", xcr=" + this.xcr + ", tds=" + this.tds + ", mpdf=" + this.mpdf + ")";
    }

    public WaiMai() {
    }

    @ConstructorProperties({"rice", "chopsticks", "xcr", "tds", "mpdf"})
    public WaiMai(String rice, String chopsticks, String xcr, String tds, String mpdf) {
        this.rice = rice;
        this.chopsticks = chopsticks;
        this.xcr = xcr;
        this.tds = tds;
        this.mpdf = mpdf;
    }

    public static class WaiMaiBuilder {
        private String rice;
        private String chopsticks;
        private String xcr;
        private String tds;
        private String mpdf;

        WaiMaiBuilder() {
        }

        public WaiMai.WaiMaiBuilder rice(String rice) {
            this.rice = rice;
            return this;
        }

        public WaiMai.WaiMaiBuilder chopsticks(String chopsticks) {
            this.chopsticks = chopsticks;
            return this;
        }

        public WaiMai.WaiMaiBuilder xcr(String xcr) {
            this.xcr = xcr;
            return this;
        }

        public WaiMai.WaiMaiBuilder tds(String tds) {
            this.tds = tds;
            return this;
        }

        public WaiMai.WaiMaiBuilder mpdf(String mpdf) {
            this.mpdf = mpdf;
            return this;
        }

        public WaiMai build() {
            return new WaiMai(this.rice, this.chopsticks, this.xcr, this.tds, this.mpdf);
        }

        public String toString() {
            return "WaiMai.WaiMaiBuilder(rice=" + this.rice + ", chopsticks=" + this.chopsticks + ", xcr=" + this.xcr + ", tds=" + this.tds + ", mpdf=" + this.mpdf + ")";
        }
    }
}

总结

好处:即最开始定义所说的:建造代码与表示分离,由于建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了(像我们上面的套餐A ,想要套餐B,只需要再定义一个套餐B即可)。

缺点:产品得组成部分必须相同,比如上面得必须品,在这里虽然很合逻辑,但是限制了使用范围

产品内部发生变化,建造者也要同步修改,后期维护成本大

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值