Java方法中的参数太多,第1部分:自定义类型

我认为构造函数和方法中冗长的参数列表是Java开发中的另一个“ 危险信号 ”,就逻辑和功能而言,它们不一定是“错误的”,但通常暗示当前或将来出现错误的可能性很高。 在一小部分帖子中,我介绍了一些可用于减少方法或构造函数的参数数量,或至少使冗长的参数列表更易读且更不易出错的方法。 每种方法都有其自己的优点和缺点。 这篇文章开始该系列文章,重点是通过使用自定义类型提高长方法/构造函数参数列表的可读性和安全性。

冗长的方法和构造方法参数列表有几个缺点。 大量参数可能很乏味,并且难以调用代码使用。 较长的参数列表也可能导致调用中参数的无意切换。 在某些情况下,可能很难找到这些错误。 幸运的是,大多数方法不必处理冗长的参数列表的另一个缺点: JVM通过编译时错误 将参数的数量限制为一个方法

自定义类型的使用是一种不减少方法或构造函数的参数数量,但确实使这些较长的参数列表更易读且不太可能以错误的顺序提供的方法。 这些自定义类型可以实现为数据传输对象 (DTO), JavaBeans值对象引用对象或任何其他自定义类型(在Java中,通常是枚举 )。

这是一个人为设计的方法示例,该方法接受多个参数,其中许多参数为String类型,许多参数为boolean类型。

/**
    * Instantiate a Person object.
    * 
    * @param lastName
    * @param firstName
    * @param middleName
    * @param salutation
    * @param suffix
    * @param streetAddress
    * @param city
    * @param state
    * @param isFemale
    * @param isEmployed
    * @param isHomeOwner
    * @return 
    */
   public Person createPerson(
      final String lastName,
      final String firstName,
      final String middleName,
      final String salutation,
      final String suffix,
      final String streetAddress,
      final String city,
      final String state,
      final boolean isFemale,
      final boolean isEmployed,
      final boolean isHomeOwner)
   {
      // implementation goes here
   }

容易意外地切换它们并以错误的顺序传递它们。 尽管我通常希望减少参数,但是可以通过更改参数列表中的类型来进行一些改进。 接下来的代码清单显示了这些自定义类型的一些示例,这些示例可用于名称,地址,城市和布尔参数。

可以将三个name参数分别更改为Name的自定义类型,而不是String 。 接下来定义该Name类型。

名称.java

package dustin.examples;

/**
 * Name representation.
 * 
 * @author Dustin
 */
public final class Name
{
   private final String name;

   public Name(final String newName)
   {
      this.name = newName;
   }

   public String getName()
   {
      return this.name;
   }

   @Override
   public String toString()
   {
      return this.name;
   }
}

称呼和后缀String类型也可以替换为自定义类型,如以下两个代码清单所示。

Salutation.java

package dustin.examples;

/**
 * Salutations for individuals' names.
 * 
 * @author Dustin
 */
public enum Salutation
{
   DR,
   MADAM,
   MISS,
   MR,
   MRS,
   MS,
   SIR
}

后缀.java

package dustin.examples;

/**
 * Suffix representation.
 * 
 * @author Dustin
 */
public enum Suffix
{
   III,
   IV,
   JR,
   SR
}

其他参数也可以用自定义类型替换。 接下来的代码清单显示了可以替换boolean以提高可读性的自定义枚举。

Gender.java

package dustin.examples;

/**
 * Gender representation.
 * 
 * @author Dustin
 */
public enum Gender
{
   FEMALE,
   MALE
}

EmploymentStatus.java

package dustin.examples;

/**
 * Representation of employment status.
 * 
 * @author Dustin
 */
public enum EmploymentStatus
{
   EMPLOYED,
   NOT_EMPLOYED
}

HomeOwnerStatus.java

package dustin.examples;

/**
 * Representation of homeowner status.
 * 
 * @author Dustin
 */
public enum HomeownerStatus
{
   HOME_OWNER,
   RENTER
}

也可以使用定义的自定义类型来传递此人的地址信息,如以下代码清单所示。

StreetAddress.java

package dustin.examples;

/**
 * Street Address representation.
 * 
 * @author Dustin
 */
public final class StreetAddress
{
   private final String address;

   public StreetAddress(final String newStreetAddress)
   {
      this.address = newStreetAddress;
   }

   public String getAddress()
   {
      return this.address;
   }

   @Override
   public String toString()
   {
      return this.address;
   }
}

City.java

package dustin.examples;

/**
 * City representation.
 * 
 * @author Dustin
 */
public final class City
{
   private final String cityName;

   public City(final String newCityName)
   {
      this.cityName = newCityName;
   }

   public String getCityName()
   {
      return this.cityName;
   }

   @Override
   public String toString()
   {
      return this.cityName;
   }
}

State.java

package dustin.examples;

/**
 * Simple representation of a state in the United States.
 * 
 * @author Dustin
 */
public enum State
{
   AK,
   AL,
   AR,
   AZ,
   CA,
   CO,
   CT,
   DE,
   FL,
   GA,
   HI,
   IA,
   ID,
   IL,
   IN,
   KS,
   KY,
   LA,
   MA,
   MD,
   ME,
   MI,
   MN,
   MO,
   MS,
   MT,
   NC,
   ND,
   NE,
   NH,
   NJ,
   NM,
   NV,
   NY,
   OH,
   OK,
   OR,
   PA,
   RI,
   SC,
   SD,
   TN,
   TX,
   UT,
   VA,
   VT,
   WA,
   WI,
   WV,
   WY
}

通过实现这些自定义类型,我们原始方法的签名变得更具可读性,并且不太可能意外地以错误的顺序提供参数。 这显示在下一个代码清单中。

public Person createPerson(
      final Name lastName,
      final Name firstName,
      final Name middleName,
      final Salutation salutation,
      final Suffix suffix,
      final StreetAddress address,
      final City city,
      final State state,
      final Gender gender,
      final EmploymentStatus employment,
      final HomeownerStatus homeowner)
   {
      // implementation goes here
   }

在上面的代码清单中,编译器现在将通过不允许之前的大多数Stringboolean参数意外混合来帮助开发人员。 这三个名称仍然是一个潜在的问题,因为调用方可能会无序提供它们,但是如果我担心的话,我可以为FirstNameLastNameMiddleName编写特定的类型(类)。 相反,我更喜欢使用一个代表全名的新类,并将这三个名称全部用作其属性,但是该方法将成为以后处理Java方法的过多参数的主题。

优势与优势

在给定方法上处理多个参数时编写和使用自定义类型的优点包括代码维护者和使用API​​的开发人员的可读性。 具有多个相同类型的参数,不仅使开发人员可以轻松混合其顺序,还降低了IDE在使用代码完成功能时将适当建议与参数匹配的能力。 正确的命名可以对IDE有所帮助,但是对IDE而言,没有什么比使用这些自定义类型可以完成的静态编译时检查有用的了。 总的来说,我更愿意从运行时转移尽可能多的自动检查到编译时,并且让这些静态定义的自定义类型(而不是通用类型)来完成此任务。

此外,这些自定义类型的存在使将来更容易添加更多详细信息。 例如,将来我可以在不更改接口的情况下,将完整的状态名称或有关状态的其他详细信息添加到该枚举中。 我不可能用一个简单的String来表示状态。

成本与劣势

自定义类型方法最常被引用的缺点之一是额外的实例化和内存使用的开销。 例如, Name类需要实例化Name类本身及其封装的String 。 但是,我认为,这种争论通常是从过早优化的角度出发,而不是合理的衡量性能问题。 在某些情况下,额外的实例化过于昂贵,以至于无法证明增强的可读性和编译时检查,但是许多(也许大多数 )情况可以提供额外的实例化,而其可观察到的影响却可以忽略不计。 我很难相信使用自定义枚举而不是Stringboolean会在大多数情况下引入性能问题。

使用自定义类型而不是内置类型的另一个缺点是编写和测试这些自定义类型需要额外的精力。 但是,如本文中的示例所示,通常存在非常简单的类或枚举,并且不难编写或测试。 有了良好的IDE和良好的脚本语言(例如Groovy),它们特别容易自动编写和测试。

结论

我喜欢使用自定义类型来提高可读性,并将更多的参数类型检查负担转移到编译器上。 我没有更多地使用这种方法来提高具有非常长的参数列表的方法和构造函数的可读性的最大原因是,它本身并没有减少参数的数量。 它使长列表更易于阅读和使用,但调用方仍然必须编写笨拙的客户端代码才能调用该方法或构造函数。 因此,在改进接受一长串参数的方法时,我经常使用除自定义类型以外的技术。 这些其他技术将在以后的文章中探讨。


翻译自: https://www.javacodegeeks.com/2013/10/too-many-parameters-in-java-methods-part-1-custom-types.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值