【问题标题】:How to format methods with large parameter lists如何格式化具有大参数列表的方法
【发布时间】:2010-09-16 10:18:42
【问题描述】:

我从未见过一种很好地做到这一点的方法,我很想看看其他人是如何做到的。目前我的格式是这样的:

public Booking createVehicleBooking(Long officeId, 
                                    Long start, 
                                    Long end,
                                    String origin, 
                                    String destination, 
                                    String purpose,         
                                    String requirements, 
                                    Integer numberOfPassengers) throws ServiceException {
/*..Code..*/
}

【问题讨论】:

    标签: java formatting methods


    【解决方案1】:
    public Booking createVehicleBooking(
        Long officeId, 
        Long start, 
        Long end,
        String origin, 
        String destination, 
        String purpose,                 
        String requirements, 
        Integer numberOfPassengers)
    
    throws ServiceException {
    /*..Code..*/
    }
    

    【讨论】:

    • 如果抛出多个异常,是否也将它们垂直排列?
    • 克里斯——取决于有多少。如果足够它跑出屏幕的一侧,是的。一般规则是:如果它跑到一边,对齐它们。如果函数名太长,嵌套和缩进。
    • 这很好。我要做的唯一改变是将右括号移动到与“抛出”相同的行,以便您可以轻松地看到它是更大语句的一部分。
    【解决方案2】:

    像这样的大量参数通常(但不总是)表明您可以使用对象来表示参数集。在以下情况下尤其如此:

    • 有几种方法具有相似的大参数集,可以用带参数对象的单个方法替换。

    • 方法调用create...

    所以你上面的代码可能会变成(请原谅我的 C++,我是 Java 开发人员):

    class BuildVehicleBooking {
        Long officeId;
        Long start;
        Long end;
        String origin;
        String destination;
        String purpose;             
        String requirements;
        Integer numberOfPassengers;
    
        Booking createVehicleBooking () throws ServiceException { ... }
    }
    

    这是建造者模式。这种模式的优点是,您可以在最终调用create 方法之前,分段构建一组复杂的参数,包括参数之间如何相互关联的多种变体,甚至在新信息可用时覆盖参数结束。

    另一个潜在的优势是您可以添加一个verifyParameters 方法,在您到达最终对象creating 之前检查它们的一致性。这适用于创建对象涉及不可逆步骤的情况,例如写入文件或数据库。

    请注意,与所有模式一样,这并不适用于所有情况,也可能不适用于您的情况。如果您的代码足够简单,那么这种模式可能会过度设计它。如果代码变得杂乱无章,重构为这种模式可能是简化它的好方法。

    【讨论】:

    • 不幸的是,我认为我无法逃脱惩罚,因为这是 Web 服务的 SOAP 端点,但信息量很大。
    • 您绝对可以使用这种技术,即使是用于 Web 服务。您需要使您的类可序列化,并可能根据您用于托管 Web 服务的方式部署架构(例如,我相信轴需要,而 asp.net 会为您处理)
    • 建造者模式很有用,好建议!为了完全控制世界(线程安全),请确保 create-method 在验证它们之前复制所有参数。 (另外,小提示:使用 long 代替 Lon,使用 int 代替 Integer 并提供 getter/setter 方法。)
    • 自从输入这个答案后,我发现自己以一些非常有用的方式更多地使用了构建器模式。奇数。
    【解决方案3】:

    我倾向于使用几个对象而不是一个对象。

    这样就变成了

    public Booking createVehicleBooking(Long officeId, DateRange dates, TripDetails trip)
    

    虽然 DateRange 和 Trip 详细信息仅包含数据的相关部分。虽然可以说 dateRange 可能是行程的一部分,而 Requirements 和 Number of Passengers 可以从 TripDetails 中删除并成为请求的一部分。

    事实上,有几种方法可以对数据进行切分,但我不得不说,将您的大列表分成相关参数组并为它们构建一个对象将允许更清晰的编程风格并增加可能的重用。

    请记住,始终可以将对象嵌入对象中,从而让您拥有

    public Booking createVehicleBooking(BookingParameters parameters)
    

    而 BookingParameters 包含 TripDetails 和 DateRange 对象以及其他参数。

    【讨论】:

    • 这个问题是关于格式化的。 (有时您确实需要在重构之前使用给定的代码库 ;-)
    【解决方案4】:

    在调用端,我喜欢使用这样的 cmets 来模拟命名参数:

    booking.createVehicleBooking(
        getOfficeId(),      // Long officeId 
        startVariable,      // Long start 
        42,                 // Long end
        getOrigin(),        // String origin 
        "destination",      // String destination 
        "purpose",          // String purpose       
        "requirements",     // String requirements
        3                   // Integer numberOfPassengers
    );
    

    【讨论】:

      【解决方案5】:

      我喜欢您展示的每行一个参数的方法。我发现很容易用肉眼扫描它并查看其中的内容。

      我发现当人们使用像 Guice 这样的东西时,你通常会得到大量的参数,这使得它更容易阅读。

      【讨论】:

      • 如果您还有其他问题,请点击 按钮进行提问。
      • Manetsus,我的文字的哪一部分让你认为这是一个问题?我指出,有许多 3rd 方库最终会使用许多参数调用,其中有一个垂直的参数列表更容易阅读。
      【解决方案6】:

      Google Java Style Guide 没有直接解决这个问题,但我同意他们在 Guava 中的格式化方式,即

      com.google.common.collect.Collections2.transform:

      public static <F, T> Collection<T> transform(
          Collection<F> fromCollection, Function<? super F, T> function) {
        return new TransformedCollection<>(fromCollection, function);
      }
      

      com.google.common.collect.ImmutableRangeMap.toImmutableRangeMap

      public static <T, K extends Comparable<? super K>, V>
          Collector<T, ?, ImmutableRangeMap<K, V>> toImmutableRangeMap(
              Function<? super T, Range<K>> keyFunction,
              Function<? super T, ? extends V> valueFunction) {
        return CollectCollectors.toImmutableRangeMap(keyFunction, valueFunction);
      }
      

      我认为规则是:

      • (如果可能,尽量保持一行)
      • 在方法名和大括号后分开
      • 将参数缩进一级以将它们与正文区分开来

      就个人而言,如果我不得不中断,我更喜欢在每个参数之后中断,即

      public static Foo makeFoo(
          Foo foo,
          Bar bar,
          Baz baz)
            throws FooException {
        f();
      }
      

      【讨论】:

      • 连同这里的推理,行业参考使其从其他答案中脱颖而出。
      • 只有我觉得这种做法让代码更难阅读?我需要额外的努力才能真正弄清楚方法体的实际开始位置。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多