Java构建器(多个构造器参数)
今天看netty权威指南,第一次听说构建器,百度了几个博客,但是并没有通俗易懂一点儿的,综合别人的博客,总结如下:
1. 构建器是什么?
当创建对象需要传入多个参数的时候我们通常会根据参数的数量写不同的构造器,具体如下
public A(int a){}
public A(int a, int b){}
public A(int a, int b, int c){}
根据不同的参数调用不同的构造器,但是当参数多了的时候,这种方式不够灵活,所以会实现动态传参的方法
public A(){}
public void seta(int a){}
public void setb(int b){}
public void setc(int c){}
这种方式提高了传参的可读性,也提高了传参的灵活性,但是会增加代码行数,同时在多线程异步执行的时候导致奇怪的错误。
有没有办法解决呢?既能提高代码可读性,提高参数灵活性,又不会增加代码行数,并保证线程安全呢?
构建器模式登场,先看代码。
这里我们写一个 Person 类,并为这个类加上构建器:
- public class Person {
- private final String name;
- private final int age;
- private final String address;
- private final String phone;
- public static class Builder{
- private final String name;
- private final int age;
- private String address = null;
- private String phone = null;
- public Builder(String name,int age){
- this.name = name;
- this.age = age;
- }
- public Builder address(String val){
- address = val;
- return this;
- }
- public Builder phone(String val){
- phone = val;
- return this;
- }
- public Person builder(){
- return new Person(this);
- }
- }
- private Person(Builder builder){
- this.name = builder.name;
- this.age = builder.age;
- this.address = builder.address;
- this.phone = builder.phone;
- }
- @Override
- public String toString() {
- return "name:"+name+" age:"+age+" address:"+address+" phone:"+phone;
- }
- }
调用这个构建器的方式
public class PersonTest {
public static void main(String[] args) {
Person p = new Person.Builder("tom", 18).address("深圳").phone("110").builder();
System.out.println(p.toString());
}
}
2. 为什么使用构建器?
2.1 参数的限制
静态工厂方法与构造器都有一个共同的局限性,就是它们不能很好的扩展到大量的可选参数。就像我们上面的那个Person 类,在实际中我们会有许多的属性,性别、出生年月、爱好...对与这样的类。
2.2 重叠构造器
我们初学的时候都会选择 重叠构造器(telecoping constructor)模式 。在这种情况下,第一个构造器是实例化对象必须的参数,第二个会多一个参数,就这样叠加,最后是一个有所有参数的构造器
- public class Person {
- private final String name;
- private final int age;
- private final String address;
- private final String phone;
- public Person(String name, int age) {
- this(name,age,null);
- }
- public Person(String name, int age, String address) {
- this(name,age,address,null);
- }
- public Person(String name, int age, String address, String phone) {
- super();
- this.name = name;
- this.age = age;
- this.address = address;
- this.phone = phone;
- }
- @Override
- public String toString() {
- return "name:"+name+" age:"+age+" address:"+address+" phone:"+phone;
- }
- }
获得对象
public class PersonTest {
public static void main(String[] args) {
Person p = new Person("tom",18,null,"110");
System.out.println(p.toString());
}
}
在这个构造器中也许会有你不想要的参数,如果我们的参数变多了的话,情况就不会很好。
总结一句话:重叠构造器可行,但当有很多的参数的时候,客户端的代码就会很难编写并且不容易阅读我们在使用的时候,必须很仔细的看每一个参数的位置和含义。
2.3 JavaBeans模式
2.3.1 创建JavaBeans模式
这个时候我们还有一种替代的方式,这个就是JavaBeans模式。这种模式下,使用无参的构造方法创建对象,然后调用setter 方法给属性设置值
- public class Person {
- private String name;
- private int age;
- private String address;
- private String phone;
- public void setName(String name) {
- this.name = name;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public void setAddress(String address) {
- this.address = address;
- }
- public void setPhone(String phone) {
- this.phone = phone;
- }
- @Override
- public String toString() {
- return "name:"+name+" age:"+age+" address:"+address+" phone:"+phone;
- }
- }
使用的方式,这个相比与重叠构造器更容易的创建了对象,同时让代码跟容易的阅读。
public class PersonTest {
public static void main(String[] args) {
Person p = new Person();
p.setName("tom");
p.setAge(18);
p.setAddress("深圳");
p.setPhone("110");
System.out.println(p.toString());
}
}
2.3.2 JavaBeans模式的劣势
构造的过程分到了几个调用中,在构造JavaBeans的时候可能会不一致
类无法仅仅通过检验构造器参数的有效性来保证一致性!
对象的不一致会导致失败,JavaBeans模式阻止了把类做为不可变的可能,需要程序员做额外努力来保证它线程安全。
2.4 构建器
构建器的创建对象就比较易于创建与阅读,线程安全
等待所有的参数验证通过才会build()对象。
与构造器相比,builder 的微略优势在于,builder可以有多个可变(varargs)参数。构造器像方法一样,只有一个可变参数。因为builder利用单独的方法来设置每个参数,你想要多少个可变参数,他们就可以有多少个,知道每个setter方法都有一个可变参数。
builder模式非常灵活,可以理由单个builder构建多个对象。builder的参数可以在创建对象时进行调整
设置了参数的builder生成一个很好的抽象工厂(Abstract Factory),也就是客户端可以将这样一个builder传给方法,使该方法能为客户端创建一个或者多个对象
builder也有自己的不足,就是创建对象就必须创建它的构建器。
builder模式还比重叠构造器模式更加的冗长,因此它会在参数多的时候使用。但是我们要知道,我们可能会在设计之后还要添加参数,所以一开始就用构建器还是比较好的。
3 总结
如果类的构造器或者静态工厂中具有多个参数,设计这种类时,Builder模式就是不错的选择,特别是当大多数14:39:30参数都是可选的时候。
与重叠构造器相比,builder牧师的客户端更易与阅读和编写
与JavaBeans相比,更加的安全
Java构建器(多个构造器参数)的更多相关文章
- Java 构建器
假如我们的一个实体类有很多的属性值,但是这些属性值又是可选的.如果我们遇到这样的是类,如何设计出方便的实体类呢? 通常解决办法一: 重叠构造器 public class User { private ...
- java拦截器获取请求完整参数
public class OptLogAspect implements HandlerInterceptor { @Override public boolean preHandle(HttpSer ...
- 【读书笔记 - Effective Java】02. 遇到多个构造器参数时要考虑用构建器
类有多个可选参数的解决方案: 1. 重叠构造器模式可行,但是当有许多参数的时候,客户端代码会很难编写,并且仍然较难以阅读. 2. JavaBeans模式,调用一个无参构造器来创造对象,然后调用sett ...
- java构造器和构建器
本文摘自:https://blog.csdn.net/wh2827991/article/details/79013115 在实例化一个类的过程中,通常会遇到多个参数的构造函数,但如果有些参数是非必需 ...
- Java 构造器 遇到多个构造器时要考虑用构建器
静态工厂和构造器有个共同的局限性:它们都不能很好地扩展到大量的可选参数. 当一个类中有若干个必选属性和多个可选属性时,采用重叠构造器模式.JavaBeans模式或者Builder模式,但各有优劣. 当 ...
- Java构造器与构建器的使用
我们在平常类的构建过程中,可能会面临很多问题,可扩张性.安全性等等.想象一下,这样一个场景,我们现在要创建一个类,其中有6个属性,其中又有4个属性的值是不太确定的(可能某个对象就不需要其中的某个值), ...
- 构造器参数过多时考虑使用构建器(Builder)
一.静态工厂和构造器的局限性 面对需要大量可选参数才能构建对象时,静态工厂和构造器并不能随着可选参数的增加而合理扩展. 假设创建一个类Person需要使用大量的可选参数,其中两个参数是必填的,剩下的都 ...
- Effective JAVA 创建和销毁对象 遇到多参构造器考虑使用构建器
//构建器抽象类,为不同类的实现提供 public interface Builder<T> { public T build(); } /** * @描述: 营养表 */ public ...
- Item 2---遇到构造器具有多个参数时,要考虑用构建器;Builder模式
问题,面对这种一个构造器具备多个参数的问题,现有的做法是使用重叠构造器的方式,该方式存在的问题: public class NutritionFacts { private final int ser ...
随机推荐
- ubuntu下如何开机自动执行自定义脚本?
答: 将自定义脚本(假设自定义的脚本绝对路径为~/start_test.sh)添加到/etc/init.d/目录下,并更新系统启动项,命令如下: sudo cp ~/start_test.sh /et ...
- ubuntu18 更换屏幕分辨率
ubuntu18.04怎么修改屏幕分辨率 最近在自己的电脑中安装了ubuntu18.04系统,默认分辨率不对所以只好自己修改分辨率,但是在桌面右键并没找到设置分辨率的选项,那么我们应该在哪里设置分辨率 ...
- ISO/IEC 9899:2011 条款6.7——声明
6.7 声明 语法 1.declaration: declaration-specifiers init-declarator-listopt ; static_assert-declar ...
- 泡泡一分钟:Robust and Fast 3D Scan Alignment Using Mutual Information
Robust and Fast 3D Scan Alignment Using Mutual Information 使用互信息进行稳健快速的三维扫描对准 https://arxiv.org/pdf/ ...
- matlab学习笔记1--matlab工作界面
一起来学matlab-matlab学习笔记1--matlab工作界面 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考书籍 <matlab 程序设计与综合应用>张德丰等著 感谢 ...
- Flink assignAscendingTimestamps 生成水印的三个重载方法
先简单介绍一下Timestamp 和Watermark 的概念: 1. Timestamp和Watermark都是基于事件的时间字段生成的 2. Timestamp和Watermark是两个不同的东西 ...
- SET IDENTITY_INSERT的用法,具体去体验一下
如果将值插入到表的标识列中,需要启用 SET IDENTITY_INSERT. 举例如下: 创建表Orders.Products,Orders表与Products表分别有标识列OrderID与Prod ...
- 基于 Egg.js 框架的 Node.js 服务构建之用户管理设计
前言 近来公司需要构建一套 EMM(Enterprise Mobility Management)的管理平台,就这种面向企业的应用管理本身需要考虑的需求是十分复杂的,技术层面管理端和服务端构建是架构核 ...
- CentOS 6 新装服务器部署流程
1.设置时区 rm -f /etc/localtime cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 2.配置内网IP (如果是外网IP,li ...
- Linux下操作数据库
一.安装数据库 1.卸载旧版本 检查是否安装有MySQL Server:rpm -qa | grep mysql rpm -e mysql_libs //普通删除模式 rpm -e --nod ...