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

        

  • 相关阅读:
    禁用aspx页面的客户端缓存
    水晶报表的自动换行(转)
    ORACLE锁的管理
    同时使用有线和无线
    Oracle系统表的查询
    Oracle中临时表的深入研究
    我的My Life Rate
    [学习笔记]c#Primer中文版命名空间
    出差兰州·火车上
    [学习笔记]c#Primer中文版类设计、static成员、const和readonly数据成员
  • 原文地址:https://www.cnblogs.com/zdd-java/p/6814314.html
Copyright © 2020-2023  润新知