【原】使用Builder模式替代构造参数传参
前言:关于传递参数,当参数过多的时候我们可以考虑使用建造者模式。
#没用 Builder模式 之前是这样传参的:
如下所示,构造方法里面的参数一大堆,看起来就非常的混乱。
用了Builder模式之后是这样的
新建一个静态内部类Buider,通过它来构建参数,然后返回一个新的对象,最后在新的对象内部把值赋给当前类的成员变量,如下图:
可以看到改造后的代码,只存在一个Buider静态内部类,瞬间感觉清晰了不少。
附加一个简单的demo:
class User {
// 下面是“一堆”的属性
private String name;
private String password;
private String nickName;
private int age; // 构造方法私有化,不然客户端就会直接调用构造方法了
private User(String name, String password, String nickName, int age) {
this.name = name;
this.password = password;
this.nickName = nickName;
this.age = age;
}
// 静态方法,用于生成一个 Builder,这个不一定要有,不过写这个方法是一个很好的习惯,
// 有些代码要求别人写 new User.UserBuilder().a()...build() 看上去就没那么好
public static UserBuilder builder() {
return new UserBuilder();
} public static class UserBuilder {
// 下面是和 User 一模一样的一堆属性
private String name;
private String password;
private String nickName;
private int age; private UserBuilder() {
} // 链式调用设置各个属性值,返回 this,即 UserBuilder
public UserBuilder name(String name) {
this.name = name;
return this;
} public UserBuilder password(String password) {
this.password = password;
return this;
} public UserBuilder nickName(String nickName) {
this.nickName = nickName;
return this;
} public UserBuilder age(int age) {
this.age = age;
return this;
} // build() 方法负责将 UserBuilder 中设置好的属性“复制”到 User 中。
// 当然,可以在 “复制” 之前做点检验
public User build() {
if (name == null || password == null) {
throw new RuntimeException("用户名和密码必填");
}
if (age <= 0 || age >= 150) {
throw new RuntimeException("年龄不合法");
}
// 还可以做赋予”默认值“的功能
if (nickName == null) {
nickName = name;
}
return new User(name, password, nickName, age);
}
}
}核心是:先把所有的属性都设置给 Builder,然后 build() 方法的时候,将这些属性复制给实际产生的对象。 看看客户端的调用: public class APP {
public static void main(String[] args) {
User d = User.builder()
.name("foo")
.password("pAss12345")
.age(25)
.build();
}
}
2018年1月19日 10:20:12 更新
附加一个swagger中看到的建造者模式:
/*
*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/ package springfox.documentation.builders; import com.fasterxml.classmate.ResolvedType;
import com.google.common.base.Optional;
import springfox.documentation.schema.ModelReference;
import springfox.documentation.service.AllowableValues;
import springfox.documentation.service.Parameter;
import springfox.documentation.service.VendorExtension; import java.util.List; import static com.google.common.collect.Lists.newArrayList;
import static springfox.documentation.builders.BuilderDefaults.*; public class ParameterBuilder {
private String name;
private String description;
private String defaultValue;
private boolean required;
private boolean allowMultiple;
private AllowableValues allowableValues;
private String paramType;
private String paramAccess;
private ResolvedType type;
private ModelReference modelRef;
private boolean hidden;
private List<VendorExtension> vendorExtensions = newArrayList(); /**
* Copy builder
*
* @param other parameter to copy from
* @return this
*/
ParameterBuilder from(Parameter other) {
return name(other.getName())
.allowableValues(other.getAllowableValues())
.allowMultiple(other.isAllowMultiple())
.defaultValue(other.getDefaultValue())
.description(other.getDescription())
.modelRef(other.getModelRef())
.parameterAccess(other.getParamAccess())
.parameterType(other.getParamType())
.required(other.isRequired())
.type(other.getType().orNull())
.hidden(other.isHidden())
.vendorExtensions(other.getVendorExtentions());
} /**
* Updates the parameter name
*
* @param name - name of the parameter
* @return this
*/
public ParameterBuilder name(String name) {
this.name = defaultIfAbsent(name, this.name);
return this;
} /**
* Updates the description of the parameter
*
* @param description - description
* @return this
*/
public ParameterBuilder description(String description) {
this.description = defaultIfAbsent(description, this.description);
return this;
} /**
* Updates the default value of the parametr
*
* @param defaultValue - default value
* @return this
*/
public ParameterBuilder defaultValue(String defaultValue) {
this.defaultValue = defaultIfAbsent(defaultValue, this.defaultValue);
return this;
} /**
* Updates if the parameter is required or optional
*
* @param required - flag to indicate if the parameter is required
* @return this
*/
public ParameterBuilder required(boolean required) {
this.required = required;
return this;
} /**
* Updates if the parameter should allow multiple values
*
* @param allowMultiple - flag to indicate if the parameter supports multi-value
* @return this
*/
public ParameterBuilder allowMultiple(boolean allowMultiple) {
this.allowMultiple = allowMultiple;
return this;
} /**
* Updates if the parameter is bound by a range of values or a range of numerical values
*
* @param allowableValues - allowable values (instance of @see springfox.documentation.service.AllowableListValues
* or @see springfox.documentation.service.AllowableRangeValues)
* @return
*/
public ParameterBuilder allowableValues(AllowableValues allowableValues) {
this.allowableValues = emptyToNull(allowableValues, this.allowableValues);
return this;
} /**
* Updates the type of parameter
*
* @param paramType - Could be header, cookie, body, query etc.
* @return this
*/
public ParameterBuilder parameterType(String paramType) {
this.paramType = defaultIfAbsent(paramType, this.paramType);
return this;
} /**
* Updates the parameter access
*
* @param paramAccess - parameter access
* @return this
*/
public ParameterBuilder parameterAccess(String paramAccess) {
this.paramAccess = defaultIfAbsent(paramAccess, this.paramAccess);
return this;
} /**
* Updates the type of parameter
*
* @param type - represents the resolved type of the parameter
* @return this
*/
public ParameterBuilder type(ResolvedType type) {
this.type = defaultIfAbsent(type, this.type);
return this;
} /**
* Represents the convenience method to infer the model reference
* Consolidate or figure out whats can be rolled into the other.
*
* @param modelRef
* @return
*/
public ParameterBuilder modelRef(ModelReference modelRef) {
this.modelRef = defaultIfAbsent(modelRef, this.modelRef);
return this;
} /**
* Updates if the parameter is hidden
*
* @param hidden - flag to indicate if the parameter is hidden
* @return this
*/
public ParameterBuilder hidden(boolean hidden) {
this.hidden = hidden;
return this;
} /**
* Updates the parameter extensions
*
* @param extensions - parameter extensions
* @return this
*/
public ParameterBuilder vendorExtensions(List<VendorExtension> extensions) {
this.vendorExtensions.addAll(nullToEmptyList(extensions));
return this;
} public Parameter build() {
return new Parameter(
name,
description,
defaultValue,
required,
allowMultiple,
modelRef,
Optional.fromNullable(type),
allowableValues,
paramType,
paramAccess,
hidden,
vendorExtensions);
}
}
总结:
相比只通过一个构造器创建实例,JavaBean模式的实例的构造过程被分成了好几个过程。
我们完全有可能在属性不完整的情况下使用这个实例。
当然,Builder也有缺点。
缺点1.创建实例前都要创建一个Builder实例。
缺点2.Builder模式编写起来较为冗长。
但是,当构建一个实例需要很多步骤(或者很多让人混淆的参数)的时候,Builder模式是个不错的选择。
【原】使用Builder模式替代构造参数传参的更多相关文章
- python笔记之强制函数以关键字参数传参
最近学习python,学到了函数传参,看到了以下这个特殊情况,特此来做个笔记 def add(*, x, y): print(x, y) 以上函数定义后,该怎么传参?前面的那个*号是做什么用的? 我们 ...
- Vue系列之 => 使用钩子函数的第二个参数传参
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Hibernate的HQL语句中定位参数和具名参数传参
HQL查询: 1.有关hql查询语句中的问号参数形式,如果出现有多个问号,这对后面设置参数就比较麻烦. 如:from User user where user.name=? and user.age= ...
- 02.当构造参数过多时使用builder模式
前言 <Effective Java>中文第三版,是一本关于Java基础的书,这本书不止一次有人推荐我看.其中包括我很喜欢的博客园博主五月的仓颉,他曾在自己的博文<给Java程序猿们 ...
- 解析《Effective Java》之多个构造器、Javabeans模式和Builder模式
最近看<Effective Java>这本被很多同行称为神作的书,但是这本书很多地方缺少了举例不好懂,下面是关于我对书上知识的理解. 一.<Effective Java>中文版 ...
- Builder模式在Java中的应用
在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...
- Builder模式(建造者模式)
在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...
- Builder模式在Java中的应用(转)
在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...
- Builder模式详解及其在Android开发中的应用
一.引言 在Android开发中,采用Builder模式的代码随处可见,比如说Android系统对话框AlertDialog的使用或者是Android中的通知栏(Notification)的使用,又比 ...
随机推荐
- 解决DbContext对象创建问题
解决DbContext对象创建问题 方法一: 使用CallContext public class BaseController : Controller { public MyContext db ...
- Python 将字典的元素按照键或者值的大小进行排序
在开发的过程中有时遇到这样的需求,一个字典里保存了一份完整的数据,其中键是一个id,值是时间,需要获取最新的5条数据,处理方式如下: 假设字典数据的变量名为my_dict data_list = so ...
- 源码编译安装lnmp环境(nginx-1.14.2 + mysql-5.6.43 + php-5.6.30 )------踩了无数坑,重装了十几次服务器才会的,不容易啊!
和LAMP不同的是,LNMP中的N指的是Nginx(类似于Apache的一种web服务软件),并且php是作为一个独立服务存在的,这个服务叫做php-fpm,Nginx直接处理静态请求,动态请求会转发 ...
- jvm内存结构(二)(栈的变化,机器指令的格式/执行模式)
栈的结构: <Java虚拟机原理图解>4.JVM机器指令集 局部变量表: 方法执行时,虚拟机会把字节码中方法数据区的code类型的属性中的局部变量放到栈的局部变量表中. 操作栈: jvm指 ...
- 解决chrome无法启用印象笔记-剪藏功能
新版Chrome浏览器安全的问题,导致从印象笔记官网下载的rxs(crx)文件无法直接通过drap&drop功能添加功能块.可以将rxs(crx)文件后缀名改成rar格式,然后解压,通 ...
- js中call、apply、bind的使用
写在前面的话 这三个方法都是来自Function.prototype上,所以所有的函数都可以使用. 他们有一个共同点,就是可以指定函数执行时的内部this指向. call和apply的区别在于参数的方 ...
- 深度学习笔记(六)VGG14
Very Deep Convolutional Networks for Large-Scale Image Recognition 1. 主要贡献 本文探究了参数总数基本不变的情况下,CNN随着层数 ...
- Andrew Ng机器学习第三章——线性回归回顾
一些概念: 向量:向量在矩阵中表示为只有一列的矩阵 n维向量:N行1列的矩阵. 利用矩阵计算可以快速实现多种结果的计算. 如下图,给出四个房子大小的样本,有四个假设函数对房子价格进行预测.构造下面的矩 ...
- 关于注解Annotation第二篇
写一个注解使用类,如下: public class Test { @Code(author = "mazhi",date="20170611") private ...
- web前端之css快速入门
css简介 css概述 CSS 指层叠样式表 (Cascading Style Sheets)样式定义如何显示 HTML 元素样式通常存储在样式表中把样式添加到 HTML 4.0 中,是为了解决内容与 ...