如何在大型遗留项目中将 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 的当前用法是:
- 获取一个对象 ID,将其存储在一个变量中,稍后对其进行一些比较
- 创建列表或设置对象 ID 并向其添加对象 ID,或检查 ID 是否已包含(没有自定义比较器)
- 将对象 ID 与字符串值(例如用户输入)进行比较,有时使用
equals()
,有时使用 equalsIgnoreCase()
- 比较两个对象 ID
具体来说,我想做的是:
- 将 ID 类型从
String
重构为 Id
- 将当前方法
String getId()
重构为Id getUniqueID()
- 其中ID直接用
id.equals("String")
或id.equalsIgnoreCase("String")
与字符串比较,改成id.equals(new Id("String"))
- 添加一个新方法(使用旧名称)
String getId()
,它将 return getUniqueID().getValue()
。这是为了向后兼容依赖于旧字符串 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()
在这个大型遗留项目中,有一个核心 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 的当前用法是:
- 获取一个对象 ID,将其存储在一个变量中,稍后对其进行一些比较
- 创建列表或设置对象 ID 并向其添加对象 ID,或检查 ID 是否已包含(没有自定义比较器)
- 将对象 ID 与字符串值(例如用户输入)进行比较,有时使用
equals()
,有时使用equalsIgnoreCase()
- 比较两个对象 ID
具体来说,我想做的是:
- 将 ID 类型从
String
重构为Id
- 将当前方法
String getId()
重构为Id getUniqueID()
- 其中ID直接用
id.equals("String")
或id.equalsIgnoreCase("String")
与字符串比较,改成id.equals(new Id("String"))
- 添加一个新方法(使用旧名称)
String getId()
,它将 returngetUniqueID().getValue()
。这是为了向后兼容依赖于旧字符串 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()