建造者模式浅谈 与工厂模式的区别

本文深入探讨建造者模式在解决构造器参数过多问题的应用,对比工厂模式,阐述其在多线程安全、参数灵活设定及避免实例化并发问题的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

创建对象时构造器参数太多怎么办? 并且后期迭代可能出现新的成员变量岂不是要写参数?

  所以用builder模式 即建造者模式,用在

1、5个或者5个以上的成员变量

2、参数不多,但是在未来,参数会增加

3、保证实例的初始化 (这点我们在下面代码中体现)

用两个实例的代码演示

第一种

1 首先我们来看通常我们

public class Cook {
    //我们以做菜为例! 嘿嘿嘿
    private int cong; //葱
    private int jiang;//姜
    private int suan;//蒜
    private int bajiao;//八角
    private int ganlajiao;//干辣椒
    private int guipi;//桂皮
    //等.....香叶  盐  味精  鸡精  酱油  醋  老抽

    //第一个构造方法  这个人只用 葱  姜 做菜
    public Cook(int cong, int jiang) {
        this.cong = cong;
        this.jiang = jiang;
    }
    //第二个构造方法   做这个菜  只用 葱  姜  蒜  做菜
    public Cook(int cong, int jiang, int suan) {
        this.cong = cong;
        this.jiang = jiang;
        this.suan = suan;
    }
    //第三个构造方法   做这个菜  只用 葱  姜  蒜  干辣椒
    public Cook(int cong, int jiang, int suan, int ganlajiao) {
        this.cong = cong;
        this.jiang = jiang;
        this.suan = suan;
        this.ganlajiao = ganlajiao;
    }
    //第四个构造方法  做这个菜  全用了 葱  姜  蒜  八角 干辣椒 桂皮
    public Cook(int cong, int jiang, int suan, int bajiao, int ganlajiao, int guipi) {
        this.cong = cong;
        this.jiang = jiang;
        this.suan = suan;
        this.bajiao = bajiao;
        this.ganlajiao = ganlajiao;
        this.guipi = guipi;
    }
    //还有好多构造方法等等.........
    public int getCong() {
        return cong;
    }

    public void setCong(int cong) {
        this.cong = cong;
    }

    public int getJiang() {
        return jiang;
    }

    public void setJiang(int jiang) {
        this.jiang = jiang;
    }

    public int getSuan() {
        return suan;
    }

    public void setSuan(int suan) {
        this.suan = suan;
    }

    public int getBajiao() {
        return bajiao;
    }

    public void setBajiao(int bajiao) {
        this.bajiao = bajiao;
    }

    public int getGanlajiao() {
        return ganlajiao;
    }

    public void setGanlajiao(int ganlajiao) {
        this.ganlajiao = ganlajiao;
    }

    public int getGuipi() {
        return guipi;
    }

    public void setGuipi(int guipi) {
        this.guipi = guipi;
    }
}

上面的代码弊端有3点   1  构造方法太多   2  对于所有调料都加的构造方法具体调用的时候传参数太多

3  当我们使用set 方法初始化对象的实际数据时候可能在多线程下不安全,未初始化完毕就把实例拿走使用,这是开发者只能自己额外的多做写保证线程安全的一些工作。

对于上面这三点建造者模式可以优雅的避开这些弊端代码如下:

public class CookBuildTest {
    private int cong; //葱
    private int jiang;//姜
    private int suan;//蒜
    private int bajiao;//八角
    private int ganlajiao;//干辣椒
    private int guipi;//桂皮
    public static class Builder {
        private int cong; //葱
        private int jiang;//姜
        private int suan;//蒜
        private int bajiao;//八角
        private int ganlajiao;//干辣椒
        private int guipi;//桂皮

        public Builder() {

        }

        public int getCong() {
            return cong;
        }
        //注意这里返回了Builder
        public Builder BuilderCong(int cong) {
            this.cong = cong;
            return this;
        }

        public int getJiang() {
            return jiang;
        }
        //注意这里返回了Builder
        public Builder BuilderJiang(int jiang) {
            this.jiang = jiang;
            return this;
        }

        public int getSuan() {
            return suan;
        }
        //注意这里返回了Builder
        public Builder BuilderSuan(int suan) {
            this.suan = suan;
            return this;
        }

        public int getBajiao() {
            return bajiao;
        }
        //注意这里返回了Builder
        public Builder BuilderBajiao(int bajiao) {
            this.bajiao = bajiao;
            return this;
        }

        public int getGanlajiao() {
            return ganlajiao;
        }
        //注意这里返回了Builder
        public Builder BuilderGanlajiao(int ganlajiao) {
            this.ganlajiao = ganlajiao;
            return this;
        }

        public int getGuipi() {
            return guipi;
        }
        //注意这里返回了Builder
        public Builder BuilderGuipi(int guipi) {
            this.guipi = guipi;
            return this;
        }
        //当建造完对象后以此方法返回一个对应建造的对象,仔细体会!这里可以避免实例化对象产生并发

//的问题,因为只有当程序调用到此方法的时候才会实例化目标对象,想想,如果不使用此种巧妙方式,而用

//set 方法,很可能导致new 出实例,还没来及set  就把对象用了,所以这也是我们私有化目标对象的构造器的原因!!!!
        public CookBuildTest build(){
            return  new CookBuildTest(this);
        }
    }
        //注意:我们使用建造者模式本意识想用建造类来创建产品对象即javaBean 所以要私有构造器,避免并发产生的问题!!!!
// 这里表现出了原理,我们想要对象实例,不在直接创建,而是通过Builder  类似于前置返给我们一个对象实例!!!
    private CookBuildTest (Builder builder){
        this.cong = builder.cong;
        this.bajiao = builder.bajiao;
        this.ganlajiao = builder.ganlajiao;
        this.guipi = builder.guipi;
        this.suan = builder.suan;
        this.jiang = builder.jiang;

    }
}

最后我们来比对下这两个使用建造模式创建的对象 和不使用建造模式创建对象调用上的区别

未使用建造模式对应的调用

 public static void main(String[] args) {
        Cook cook = new Cook(2, 2, 2);
        //发现需要桂皮,而构造参数又没有那么就set  ,
        // 相应的你可能想为啥不定义一个构造器省着 set了呢,这就又回答了一个问题上,我们的类中将会有越来越多的构造器这显然不合适
        cook.setGuipi(2);   //这里就会存在线程问题,可能这个对象实例创建完成后,此行代码还未执行就掉用 了cook 实例
    }

 使用建造模式

public static void main(String[] args) {
        //通过新建建造类来创建实例
        CookBuildTest build = new CookBuildTest.Builder()
                .BuilderCong(2).BuilderSuan(3).BuilderGanlajiao(4)
                .build();   //最终参数初始化完后build 返回CookBuildTest
    }

看用来建造者模式我们在掉用的时候不用再考虑类的构造器了,而是想初始化哪些量就直接点出来,并且最后build 是最后返回产品的实例 了!!!

总结:思想上原理是在创建一个对象的时 我们并不直接对操作对象,而是通过一个前置类【前置是指:我想建造一个对象所传的参数先用另一个类来存储参数,这个类往往就是建造类,所以建造类的成员属性往往都和最终要创建的对象是相同的。】(建造类【这里说明下,此建造类可以使抽象建造类的实现类】)让他创建初始化完成后我们直接使用前置类返给的对象来用!!

建造者模式应用场景如下:

  1构造器太多,入参组合变化太多。

2  实例化对象是依赖,各个组件的产生以及装配顺序,关注一步一步组装对象。

   注意:这里大家可能会想,工厂模式也是为了实例化目标对象,屏蔽实例化对象的复杂细节,有什么区别吗?

       客户参与度关心点

          建造者让我们调用者参与程度很高,每个参数的值都是我们参与调用的。所以我们很关心每个数值

           工厂模式,参数值相对比较固定(举个例子,一个数据源对象他有很多配置,最大连接数,最小连接数,空闲连接数.....等等,可是你发现很多参数基本调好后都是固定的),所以我们对每个数值并不太关心,更关心的是这个对象整体,工厂你实例化一个对象,屏蔽复杂的细节,给我对象就完了

其实最规范的建造者是如下步骤:

已经整理了脑图供参考

       后续人多再更新脑图的代码和解释

  • 感谢您的阅读。如果感觉文章对您有用,麻烦您动动手指点个赞,以资鼓励。谢谢!
  • 转载请注明出处哈 

    赠人玫瑰,手有余香,你的关注,我的动力

    更多分享可见:

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值