【原】使用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模式是个不错的选择。

    

转载于:https://www.cnblogs.com/zdd-java/p/6814314.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值