如何在大型遗留项目中将 String id 重构为 class Id?

How to refactor String id to class Id in a big legacy project?

在这个大型遗留项目中,有一个核心 class MyObject,其 ID 属性 已被编码为字符串。在整个项目中的任何地方都可以访问此 ID。

public class MyObject {
  private String id;

  public String getId(){
    return id;
  }
}

我正在研究使用以下方法将此字符串 属性 重构为类型 class 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 的当前用法是:

具体来说,我想做的是:

当然,我可以只列出 属性、它的 getter 和 setter 的所有用法,然后手动替换它们。有时,我可能可以使用正则表达式,但这可能不是什么好主意。此外,这简直令人望而生畏,因为有 500 多种用法可以在几十个 classes 中进行编辑,包括子 classes。

我看过IDEA的refactor: type migrate功能,但是好像做不到。我通常不在 IDEA 中工作,所以我可能做错了什么,但它告诉我有几百个冲突并且它无法转换的东西列表相当长。

我似乎无法提供旧 getter getId() 到新 getUniqueID().getValue() 的映射,例如

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

需要映射到

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

我想这种重构应该很流行,但到目前为止,我似乎必须主要通过手工和搜索+替换来完成。

有没有自动化的方法?也许,一些重构工具可以指定旧的使用模式如何映射到新的使用模式?

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

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

ID getUniqueID() {
    //TODO
}

仅在必要且有明显好处的地方手动编辑 getId().getValue().equals("test") 次。

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

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

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

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

为了向后兼容,正如@c0der 所建议的,旧的 getter 会 return newIdObject.getValue()