【问题标题】:Best practice when there is constructor change in java objectsjava对象中构造函数更改时的最佳实践
【发布时间】:2016-09-12 00:21:39
【问题描述】:

我有一个类,其中根据新的 api 集成添加了许多参数。

例如,之前我有一个有 4 个参数的类:

Integer a;
String b;
Map<String, String> c;
List<Integer> e.

所以构造函数是:

public SampleClass(Integer a, 
                   String b, 
                   Map<String, String> c,      
                   List<Integer> e) 
{
    this.a = a;
    this.b = b;
    this.c = c;
    this.e = e;
}

几个团队已经在他们的代码中使用这个构造函数与我的 API 集成。 过了一段时间,这个类中添加了一个新参数。即

Double d;

所以我添加了一个新的构造函数:

public SampleClass(Integer a,
                   String b,
                   Map<String, String> c,
                   List<Integer> e,
                   Double d)
{
    this.a = a;
    this.b = b;
    this.c = c;
    this.e = e;
    this.d = d;
}

我将之前的构造函数标记为已弃用。我没有删除以前的构造函数,因为如果删除,客户端的代码会中断。

随着新参数的添加,我现在有了带有 5 个参数的构造函数。

是否有关于如何弃用/删除构造函数的最佳实践,以免发生这种情况?

【问题讨论】:

  • 不确定这是否是个好主意,但您可以尝试使用Lombok builder 模式。唯一的问题(我想知道这是否是您的答案)是 Lombok 依赖于以这种方式创建实例:Type.builder.param1(valueParam1).others(valueOthers).(...) ... (...).build,这是您以前的客户所没有的。可是你跟他们谈判,他们做不到吗?我的意思是 Lombok 为您提供了一个独立于参数顺序和数字的自我管理的构造函数。
  • 使用builder Pattern 并在当前班级使用overloading 为constracturs
  • 我认为应该使用Builder模式
  • 最重要的是要有一个清晰且有文档记录的 API 演进策略。因此,无论您选择哪种方式,您都需要始终如一地遵循它,并且需要记录它。

标签: java design-patterns api-design


【解决方案1】:

为什么不使用可变参数构造函数。这样你可以将任意数量的参数传递给构造函数。

例如:

公开双平均(双...数字){

       double total = 0.0; // initialize total

      // calculate total using the enhanced for statement
      for ( double d : numbers )              
         total += d;                          

      return total / numbers.length;
   } // end method average

【讨论】:

  • 答案与问题不匹配。
  • 请详细说明。在我看来,它确实匹配。
  • 构造函数的属性并不总是双倍的。如果你想添加 int[] 作为新属性,你会怎么做?
【解决方案2】:

从以下位置更改旧构造函数:

public SampleClass(Integer a, 
                   String b, 
                   Map<String, String> c,      
                   List<Integer> e) 
{
    this.a = a;
    this.b = b;
    this.c = c;
    this.e = e;
}

public SampleClass(Integer a, 
                   String b, 
                   Map<String, String> c,      
                   List<Integer> e) 
{
    //Zero is passed as a default value, but you can pass anything you want
    this(a,b,c,e,0);
}

这样它会在后台调用新的。

不过,您没有提供足够的信息来说明应在多大程度上支持旧版本。如果根本不应该,您应该从代码中删除它。这样,您将强制 API 的用户分析更改的内容并连接新的构造函数。

如果你不这样做,他们会继续使用旧的,因为程序员很懒 :-)

【讨论】:

  • 这与懒惰无关。当你发布一个 API 时,你就做出了一个承诺。兑现承诺是您的责任。
  • 是的,但是如果API必须改变并且确实改变了,程序员应该负责并分析更新到新版本时发生了什么变化。实际上,如果代码编译并且测试通过,我们大多数人会简单地假设没有任何改变。而@Deprecated 几乎没有解决这个问题 :-D 因此,如果由于某种原因更改至关重要,那么从 API 中删除方法是表示用户应该分析更改内容和原因的好方法。如果他们不想这样做,因为他们相信 API 的原样,他们总是可以避免更新,以新功能、更改等为代价。C'est la vie
  • 您只希望在主要版本更改时强制 API 更改,这是惯例。正如我在另一条评论中所说,重要的是您对如何处理此类实例有一个非常明确的政策。
【解决方案3】:

关注Open/closed principle 会有所帮助。当需要新功能时,不应修改您最初编写的类,而应从它派生另一个类以扩展其功能。

【讨论】:

  • 但是随着新参数的逐渐添加,不会创建新的类。管理所有这些类会不会很困难?
猜你喜欢
  • 2010-11-14
  • 1970-01-01
  • 2018-10-13
  • 1970-01-01
  • 2017-09-13
  • 1970-01-01
  • 2011-04-17
  • 2022-11-04
  • 2010-10-04
相关资源
最近更新 更多