常用的建造者模式

建造者模式也叫生成器模式

它的作用是:

  • 分离复杂对象的构建和表示
  • 同样的构建过程可以创建不同的表示
  • 无需记忆,自然使用 (无需刻意使用,你会发现你已经使用过)

经过我的学习,我个人觉得这个模式与模板方法特别像

我们先来简单看一下他的类图:

在这里插入图片描述

这里值得说一下的是,这个类图其实经过时间的发展已经有一些被进化了,现在更多的是用链式操作直接进行对象的创建,具体怎么使用看下边例子吧。

一、T2级 找对象

话说程序员相亲大会来了。

给女生定义了几个属性:身高、年龄、长相、胸围、腰围、臀围、工资、性格、籍贯

有以下几位嘉宾:

小明想找一个限定身高、限定工资的女生。

小亮想找一个限定性格、限定胸围的女生。

小路想找一个限定性格、限定腰围的女生。

我们怎么设计这个类呢。

按照T2级别的思路,我们会用多参数构造函数来实现这个功能

package builder;/*** @author 木子的昼夜编程*/
public class Girl {// 身高 cmprivate Integer height;// 年龄private Integer age;// 长相private String face;// 胸围 cmprivate Integer bust;// 腰围 cmprivate Integer waist;// 臀围 cmprivate Integer hipline;// 工资 元private Integer salary;// 性格private String nature;// 籍贯private String nativePlace;// 1. 为了满足小明的需求我们创建一个身高、工资构造函数public Girl(Integer height, Integer salary){this.height = height;this.salary = salary;}// 2. 为了满足小亮的需求 我们创建一个性格、胸围构造函数/*public Girl(String nature, Integer bust){this.nature =  nature;this.bust = bust;}*/// 3. 为了满足小路的需求 我们创建一个性格、腰围构造函数// 这时候你会发现 根本不能这样写 因为上边已经有一个参数是String Integer的构造了// 所以我们把这两个合成一个/*public Girl(String nature, Integer waist) {this.nature = nature;this.hipline = hipline;}*/// 4. 2和3合成一个  性格+胸围+腰围public Girl(String nature, Integer bust, Integer waist) {this.nature = nature;this.bust = bust;this.waist = waist;}@Overridepublic String toString() {return "Girl{" +"height=" + height +", age=" + age +", face='" + face + '\'' +", bust=" + bust +", waist=" + waist +", hipline=" + hipline +", salary=" + salary +", nature='" + nature + '\'' +", nativePlace='" + nativePlace + '\'' +'}';}
}

这时候开始定义几个姑娘需求

package builder;/*** @author 木子的昼夜编程*/
public class Test {public static void main(String[] args) {// 小明的要求 身高170  薪资10000Girl girl01 = new Girl(170, 10000);System.out.println(girl01);// 小亮的要求 性格和善、胸围88Girl girl02 = new Girl("和善", 88, null);System.out.println(girl02);// 小路的要求 性格火辣、腰围70Girl girl03 = new Girl("和善", null, 70);System.out.println(girl03);}
}

我们可以看到用构造函数的重载实现我们的需求。实在不行我们就写一个全部参数的构造函数,需要使用哪个参数就传递哪个参数,其他参数传递空值。

这就结束了?好像还没设计建造者模式呀?

借用Effective Java的一句话:重叠构造器模式可行,但是当有许多参数的时候,客户端代码会很难编写,并且仍然较难以解读。

这句话啥意思呢,比如我们上边小亮和小路的例子,如果在使用的时候第二个参数(胸围)和第三个参数(腰围)的位置放错了会出现什么结果呢?

结果就是小亮找了个腰围很突兀的女生,小路找了个胸围很渺小的女生。

因为客户端不小心颠倒了其中参数顺序的时候,编译器是不会报错的,但是程序运行的时候,或者程序呈现的结果是会有错误的。

二、 T1级找对象

T1级别的找对象就会用到我们常用的(项目中处处可见的)JavaBeans模式

也就是我们常用的Setter方法

用setter来设置每一个需要的参数

好处:创建实例容易、代码易读

坏处:

  • JavaBeans自身很严重的缺点,那就是在构造过程中被分到几个调用中,在构造过程中JavaBean可能处于不一致的状态 ;请注意这句话不是我说的,这是Joshua Bloch说的,这个人是谁,不在本文讨论范围,我个人觉得其实一般项目中用set基本不会出现不一致问题,很少有遇到创建一个对象的时候会被多个调用者调用
  • JavaBeans模式使得把类做成笔可变的可能性不复存在(这个的意思大概是创建了对象后随时可以修改,不能固定一个最终版本,因为set可以随时调用,我还没有很懂这个,等我以后顿悟了再详细说这条)

我们来代码实现一下(其实很简单,就写set方法即可)

package builder;/*** @author 木子的昼夜编程*/
public class GirlB {// 身高 cmprivate Integer height;// 年龄private Integer age;// 长相private String face;// 胸围 cmprivate Integer bust;// 腰围 cmprivate Integer waist;// 臀围 cmprivate Integer hipline;// 工资 元private Integer salary;// 性格private String nature;// 籍贯private String nativePlace;public void setHeight(Integer height) {this.height = height;}public void setAge(Integer age) {this.age = age;}public void setFace(String face) {this.face = face;}public void setBust(Integer bust) {this.bust = bust;}public void setWaist(Integer waist) {this.waist = waist;}public void setHipline(Integer hipline) {this.hipline = hipline;}public void setSalary(Integer salary) {this.salary = salary;}public void setNature(String nature) {this.nature = nature;}public void setNativePlace(String nativePlace) {this.nativePlace = nativePlace;}@Overridepublic String toString() {return "Girl{" +"身高要求:" + height +", 年龄要求:" + age +", 长相要求'" + face + '\'' +", 胸围要求:" + bust +", 腰围要求:" + waist +", 臀围要求:" + hipline +", 薪资要求" + salary +", 性格要求:'" + nature + '\'' +", 籍贯要求:'" + nativePlace + '\'' +'}';}
}

这时候再来给小明、小亮、小路创建对象

package builder;/*** @author 木子的昼夜编程*/
public class Test02 {public static void main(String[] args) {// 小明的要求 身高170  薪资10000GirlB girl01 = new GirlB();girl01.setHeight(170);girl01.setSalary(10000);System.out.println(girl01);// 小亮的要求 性格和善、胸围88GirlB girl02 = new GirlB();girl02.setNature("性格和善");girl02.setBust(88);System.out.println(girl02);// 小路的要求 性格火辣、腰围70GirlB girl03 = new GirlB();girl03.setNature("性格火辣");girl03.setWaist(70);System.out.println(girl03);}
}

这样就比较好了,想要什么属性就单独设置那个属性就可以了。

三、T0 级找对象

幸运的是我呢还有第三种替代方式,它既能保证与重叠构造器模式那样安全,也能保证像JavaBeans模式那么好的可读性。这就是建造者(Builder)模式

最最最前边我们画了一个类图,但是我不按照那个图写demo,为什么?任性呗。

你一定要懂,设计模式不是一个固定模板,而是一种思想。

package builder;/*** @author 木子的昼夜编程*/
public class GirlC {// 身高 cmprivate Integer height;// 年龄private Integer age;// 长相private String face;// 胸围 cmprivate Integer bust;// 腰围 cmprivate Integer waist;// 臀围 cmprivate Integer hipline;// 工资 元private Integer salary;// 性格private String nature;// 籍贯private String nativePlace;// 建造者public static class Builder{// 身高 cmprivate Integer height;// 年龄private Integer age;// 长相private String face;// 胸围 cmprivate Integer bust;// 腰围 cmprivate Integer waist;// 臀围 cmprivate Integer hipline;// 工资 元private Integer salary;// 性格private String nature;// 籍贯private String nativePlace;public Builder setHeight(Integer height) {this.height = height;return this;}public Builder setAge(Integer age) {this.age = age;return this;}public Builder setFace(String face) {this.face = face;return this;}public Builder setBust(Integer bust) {this.bust = bust;return this;}public Builder setWaist(Integer waist) {this.waist = waist;return this;}public Builder setHipline(Integer hipline) {this.hipline = hipline;return this;}public Builder setSalary(Integer salary) {this.salary = salary;return this;}public Builder setNature(String nature) {this.nature = nature;return this;}public Builder setNativePlace(String nativePlace) {this.nativePlace = nativePlace;return this;}public GirlC build(){return new GirlC(this);}}// 先给他搞成私有的 外部不能调用 但是Builder是内部类可以直接使用private GirlC(Builder builder){// 身高 cmheight = builder.height;// 年龄age = builder.age;// 长相face = builder.face;// 胸围 cmbust = builder.bust;// 腰围 cmwaist = builder.waist;// 臀围 cmhipline = builder.hipline;// 工资 元salary = builder.salary;// 性格nature = builder.nature;// 籍贯nativePlace = builder.nativePlace;}@Overridepublic String toString() {return "Girl{" +"身高要求:" + height +", 年龄要求:" + age +", 长相要求'" + face + '\'' +", 胸围要求:" + bust +", 腰围要求:" + waist +", 臀围要求:" + hipline +", 薪资要求" + salary +", 性格要求:'" + nature + '\'' +", 籍贯要求:'" + nativePlace + '\'' +'}';}
}

我们接着给小亮、小明、小路创建对象

package builder;/*** @author 木子的昼夜编程*/
public class Test03 {public static void main(String[] args) {// 小明的要求 身高170  薪资10000GirlC girl01 = new GirlC.Builder().setHeight(170).setSalary(10000).build();System.out.println(girl01);// 小亮的要求 性格和善、胸围88GirlC girl02 = new GirlC.Builder().setNature("性格和善").setBust(88).build();System.out.println(girl02);// 小路的要求 性格火辣、腰围70GirlC girl03 = new GirlC.Builder().setNature("性格火辣").setWaist(70).build();System.out.println(girl03);}
}

可以看到我们为了写Builder类写了很多代码,无所谓,代码量不就是在这样积累的吗(哈哈)

我们开发中经常用loombook

有很多人说它不好用,代码入侵太强,那又怎么样呢。

他不喜欢任他不喜欢,我喜欢就好。

至于loombook的使用,我就不叙述了,百度一大筐,还有各种详细使用说明。

周末的一篇文章,没有写完,今天抽点儿时间补充完毕。

周一综合征的表现,比较困。

持续学习,持续输出,祝大家技术越来越强,工作越来越好。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部