- 感谢您的阅读。如果感觉文章对您有用,麻烦您动动手指点个赞,以资鼓励。谢谢!
- 转载请注明出处哈 建造者模式浅谈 与工厂模式的区别_茄子_土豆的博客-优快云博客_建造者模式和工厂模式的区别
创建对象时构造器参数太多怎么办? 并且后期迭代可能出现新的成员变量岂不是要写参数?
所以用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 实例化对象是依赖,各个组件的产生以及装配顺序,关注一步一步组装对象。
注意:这里大家可能会想,工厂模式也是为了实例化目标对象,屏蔽实例化对象的复杂细节,有什么区别吗?
客户参与度和关心点:
建造者让我们调用者参与程度很高,每个参数的值都是我们参与调用的。所以我们很关心每个数值
工厂模式,参数值相对比较固定(举个例子,一个数据源对象他有很多配置,最大连接数,最小连接数,空闲连接数.....等等,可是你发现很多参数基本调好后都是固定的),所以我们对每个数值并不太关心,更关心的是这个对象整体,工厂你实例化一个对象,屏蔽复杂的细节,给我对象就完了
其实最规范的建造者是如下步骤:
已经整理了脑图供参考
后续人多再更新脑图的代码和解释
- 感谢您的阅读。如果感觉文章对您有用,麻烦您动动手指点个赞,以资鼓励。谢谢!
- 转载请注明出处哈
赠人玫瑰,手有余香,你的关注,我的动力
更多分享可见: