1.问题背景
有这样一个背景:考虑到用一个类描述产品的成分说明书。在成分说明书中,某些标签是必需的:成分A,成分B,另外还有其他可选成分,成分C,成分D,成分E......对于这样的类,如果使用构造器来完成类对象的构造的话,是相当复杂的,因为你可能需要写许多的构造方法以满足不同产品的成分说明。
2.重叠构造器模式
在以上背景下,程序猿一般会采用重叠构造起模式。实例如下:
public class Product{
private final int proElem1;// 成份1,必需参数
private final int proElem2;//成份2,必需参数
private final int proElem3;//成份3,可选参数
private final int proElem4;//成份4,可选参数
public Product(int proElem1,int proElem2){
this.proElem1 = proElem1;
this.proElem2 = proElem2;
this(proElem1,proElem2,0,0);
}
public Product(int proElem1,int proElem2,int proElem3){
this(proElem1,proElem2,proElem3,0);
}
public Product(int proElem1,int proElem2,int proElem3,int proElem4){
this.proElem1 = proElem1;
this.proElem2 = proElem2;
this.proElem3 = proElem3;
this.proElem4 = proElem4;
}
}
你创建实例的时候就可以根据自己需要的参数创建不同的实例。上面的程序一定程序上可以使得创建实例更加清晰,但是想象一下如果类需要设置的参数特别多的情况,客户端代码会很难编写,而且比较难以阅读,如果客户端不小心颠倒了参数的顺序,编译器可能也不会出错。当遇到许多构造器参数的时候可以考虑以下方案。
3.JavaBeans模式
在这种模式下,使用一个无参的构造器来创建实例,然后使用属性的setter方法来设置属性的值,实例如下:
public class Product{
private int proElem1;
private int proElem2;
private int proElem3;
private int proElem4;
public Product(){
}
public void setProElem1(int proElem1){
this.proElem1 = proElem1;
}
public void setProElem2(int proElem2){
this.proElem2 = proElem2;
}
public void setProElem3(int proElem3){
this.proElem3 = proElem3;
}
public void setProElem4(int proElem4){
this.proElem4 = proElem4;
}
}
这种模式弥补了重叠构造器模式的不足,使得创建实例更加容易。
JavaBeans模式的缺点:实例的创建被分成了几个阶段,使得实例在程序中处于一种不一致的状态(我随时都可以设置实例的属性)。幸运的是,还有第三种方法!
3.建造者模式
建造者模式既可以像重叠构造器那么安全,又能保证像JavaBeans那样的可读性。使用Builder模式,不直接生成对象,而是让客户端利用必要的参数调用构造器,得到一个builder对象,然后在builder对象上调用类似setter的方法,来设置参数,实例如下:
public class Product{
private final int proElem1;
private final int proElem2;
private final int proElem3;
private final int proElem4;
public static class Builder{
private final int proElem1;
private final int proElem2;
private int proElem3;
private int proElem4;
public Builer(int proElem1,int proElem2){
this.proElem1 = proElem1;
this.proElem2 = proElem2;
}
public Builder proElem3(int proElem3){
this.proElem3 = proElem3;
return this;
}
public Builder proElem4(int proElem4){
this.proElem4 = proElem4;
return this;
}
public Product build(){
return new Product(this);
}
}
private Product(Builder builder){
proElem1 = builder.proElem1;
proElem2 = builder.proElem2;
proElem3 = builder.proElem3;
proElem4 = builder.proElem4;
}
}
使用Builder模式创建对象的优点:
1、客户端代码更容易编写,builder模式模拟了具名的可选参数,设置参数更加清晰;
2、通过build方法可以对参数进行约束,如果不满足条件可以抛出异常;
3、设置了参数的builder生成了一个很好的抽象工厂;
备注:定义一个范型就可以满足所有的builder
public interface Builder<T>{
public T build();
}
4.总结
如果类的构造器或者静态工厂中具有多个参数,设计这种类时,Builder模式是种不错的选择,特别是当大多数参数都是可选的时候。与传统的重叠构造器模式相比,使用Builder模式的客户端代码更易于阅读和编写,构建器也比JavaBeans更加安全。
版权声明:本文为博主原创文章,未经博主允许不得转载。
分享到:
相关推荐
《Effective Java》第三版中文版目录 第一章 介绍 1 第二章 创建和销毁对象 4 1 考虑用静态工厂方法替换构造器 4 2 当遇到多个构造器参
Effective java 3 学习记录
effective java 读书笔记,第二版自己摘要并翻译,以备速查。
effective-java.pdf
Effective Java读书笔记.pdf
Effective Java读书笔记,记载了大部分我觉的有用的东西,前半部分有代码说明,但后半部分的代码,太过琐碎,就没有整理
构建高效的Java企业级系统是项困难的工作。本书详细介绍企业级计算技术中的常见问题,并描述使用企业级Java平台技术处理这些问题的方法。本书以若干条建议、揸南的形式,言简意赅地介绍了J2EE开发中的微妙之处。无论...
【Effective Java】阅读笔记markdown 文件
effective-java 配套代码
15. 使类和成员的可访问性最小化 16. 在公有类中使用访问方法而非公有域 17.使可变性最小化:不可变类
《Effective Java》读书分享.pptx
Effective Java Effective Java Effective Java
java effective 第二版中英文二份文件,包含本书源码。
Effective Enterprise Java
记录了我的effective-Python学习笔记,精简了effective-Python中重要的部分。effective-Python是一本值得多看几遍的书,但是看后面的几遍的时候完全可以直接看自己的学习笔记。此学习笔记侧重与比较实用的部分即前四...
effectiveJava的笔记
[Addison-Wesley] Effective Java 第2版 (英文版) [Addison-Wesley] Effective Java 2nd Edition (E-Book) ☆ 出版信息:☆ [作者信息] Joshua Bloch [出版机构] Addison-Wesley [出版日期] 2008年05月28日 ...