如何在大型旧项目中将String id重构为class ID?

时间:2018-12-06 04:09:04

标签: java intellij-idea refactoring automated-refactoring

在这个大型的遗留项目中,有一个核心类MyObject,它具有ID属性,该属性已编码为String。在项目的任何地方都可以访问该ID。

public class MyObject {
  private String id;

  public String getId(){
    return id;
  }
}

我正在研究使用以下方法将此String属性重构为类型类ID的可能性:

class Id implements Comparable<Id> {
  String value
  Id(String value)
  String getValue()
  int hashCode()
  boolean equals(Object obj)
  int compareTo(Id o)
  String toString()
}

重构时,我需要牢记,尽管我可以以任何方式重构我们自己的项目,但仍有一些客户使用该项目的API,并且更改最好是向后兼容的。内部字符串ID的当前用法是:

  • 获取对象ID,将其存储在变量中,以后再进行一些比较
  • 创建列表或设置并添加对象ID,或检查是否已包含ID(没有自定义比较器)
  • 有时用equals()和有时用equalsIgnoreCase()比较对象ID和字符串值(例如用户输入)
  • 比较两个对象ID

具体地说,我想做的是:

  • 将ID的类型从String重构为Id
  • 将当前方法String getId()重构为Id getUniqueID()
  • 直接使用id.equals("String")id.equalsIgnoreCase("String")将ID与字符串进行比较时,将其更改为id.equals(new Id("String"))
  • 添加新方法(旧名称)String getId(),该方法将返回getUniqueID().getValue()。这是为了与依赖旧字符串ID的客户代码向后兼容。

当然,我可以列出该属性的所有用法,其getter和setter并手动替换它们。有时,我也许可以摆脱使用正则表达式的困扰,但这并不是一个好主意。此外,它令人生畏,因为在包括子类在内的几十个类中有500多种用法可供编辑。

我已经看过IDEA的重构:类型迁移函数,但似乎无法做到这一点。我通常不会在IDEA中工作,所以我可能做错了什么,但是它告诉我有几百个冲突,并且无法转换的内容很长。

看起来我无法提供旧的吸气剂getId()到新的getUniqueID().getValue()的映射,例如

myObject.getId().equalsIgnoreCase("test")

需要映射到

myObject.getUniqueID().getValue().equals(new Id("test"))

我认为这种重构应该会很流行,但是到目前为止,我似乎将不得不手动完成并进行搜索+替换。

是否有自动化的方法?也许,某些重构工具将允许指定旧的使用模式将如何映射到新的使用模式?

2 个答案:

答案 0 :(得分:1)

一个简单的解决方案,用于向后兼容,不需要大量的重构:

@Deprecated
String getId() {  return getUniqueID().getValue(); }

ID getUniqueID() {
    //TODO
}

仅在必不可少且明显受益的地方手动编辑getId().getValue().equals("test")个事件。

答案 1 :(得分:0)

我认为提出的问题的普遍答案确实是使用IntelliJ IDEA的功能:重构→类型迁移。

挑战在于,它可能会将许多其他变量迁移到新类型,而不仅仅是我想迁移的变量。

例如,我们还有另一个类NameDescription,它使用两个String参数作为名称和描述,有时用作new NameDescription(myObject.getId(), "Some description")。在这种情况下,IDEA认为它可能也需要将NameDescription.name从String更改为Id,这实际上是错误的。 为了避免这种情况,需要在请求类型迁移后预览使用情况,并手动排除这种情况以及其他不应该迁移的情况。

此外,IDEA的另一个功能可用于修改代码中的模式:Search / Replace从结构上讲,它允许使用变量定义搜索模式,并且比自己编写许多正则表达式更容易使用。

为了向后兼容,如@ c0der所建议,旧的getter将返回newIdObject.getValue()