更改遗留代码中的不可变 class
Changing an immutable class in legacy code
我想替换(可变)class
class OldValue {
private int value;
public OldValue(int value) { this.value = value; }
public int getValue() { return value; }
public void setValue(int value) { this.value = value; }
}
与不可变 class
class NewValue {
private final int value;
public NewValue(int value) { this.value = value; }
public int getValue() { return value; }
/* no setter, obviously */
}
在大部分代码中,newValue.set(777)
可以替换为 newValue = new NewValue(777)
。但是,代码的一些遗留部分类似于
class ManagementServiceProviderFacadeSingletonAbstractFactoryObserver {
public void setTheValue(OldValue oldValue) {
oldValue.setValue(555);
}
}
class Data {
private OldValue oldValue;
public OldValue get() { return oldValue; }
}
class SomewhereElse {
public void frobnicate(Data data, ManagementServiceProviderFacadeSingletonAbstractFactoryObserver x) {
x.setTheValue(data.get());
}
}
这些遗留部分很难改变,我们希望尽可能少地调整它。有没有办法编写某种可以在遗留代码中使用的“邪恶”setter 方法?像
class EvilSetter {
public static void evilSet(NewValue newValue, int x) {
// temporarily make newValue.value both public and non-final, set it to x
}
}
在不失去新设计的不变性和优雅性的情况下,还有其他方法吗?
我可能会保留这两种类型,让遗留代码单独使用旧类型,并提供适配器方法在两者之间进行转换。
public class LegacyValueAdapter {
public static OldValue toOldValue(NewValue newValue) {
return new OldValue(newValue.getValue);
}
public static NewValue toNewValue (OldValue oldValue) {
return new NewValue(oldValue.getValue);
}
}
清楚地记录这些应该只用于与遗留代码的接口,根据需要标记为已弃用。这显然不理想,但适用于整个情况。
如果 class 更复杂(例如,也有具有一些重要行为的方法),可能值得通过包装 NewValue
的实例来实现 OldValue
,但是在这种简单的情况下,不会提供太多好处。
我强烈建议不要进行任何反射黑客攻击,因为它们首先会使使用不可变类型的大部分好处失效。不要给我一个看起来不可变的类型,但随后会以某种方式偷偷改变值 - 这会破坏用户的期望并隐藏竞争条件的风险。
我想替换(可变)class
class OldValue {
private int value;
public OldValue(int value) { this.value = value; }
public int getValue() { return value; }
public void setValue(int value) { this.value = value; }
}
与不可变 class
class NewValue {
private final int value;
public NewValue(int value) { this.value = value; }
public int getValue() { return value; }
/* no setter, obviously */
}
在大部分代码中,newValue.set(777)
可以替换为 newValue = new NewValue(777)
。但是,代码的一些遗留部分类似于
class ManagementServiceProviderFacadeSingletonAbstractFactoryObserver {
public void setTheValue(OldValue oldValue) {
oldValue.setValue(555);
}
}
class Data {
private OldValue oldValue;
public OldValue get() { return oldValue; }
}
class SomewhereElse {
public void frobnicate(Data data, ManagementServiceProviderFacadeSingletonAbstractFactoryObserver x) {
x.setTheValue(data.get());
}
}
这些遗留部分很难改变,我们希望尽可能少地调整它。有没有办法编写某种可以在遗留代码中使用的“邪恶”setter 方法?像
class EvilSetter {
public static void evilSet(NewValue newValue, int x) {
// temporarily make newValue.value both public and non-final, set it to x
}
}
在不失去新设计的不变性和优雅性的情况下,还有其他方法吗?
我可能会保留这两种类型,让遗留代码单独使用旧类型,并提供适配器方法在两者之间进行转换。
public class LegacyValueAdapter {
public static OldValue toOldValue(NewValue newValue) {
return new OldValue(newValue.getValue);
}
public static NewValue toNewValue (OldValue oldValue) {
return new NewValue(oldValue.getValue);
}
}
清楚地记录这些应该只用于与遗留代码的接口,根据需要标记为已弃用。这显然不理想,但适用于整个情况。
如果 class 更复杂(例如,也有具有一些重要行为的方法),可能值得通过包装 NewValue
的实例来实现 OldValue
,但是在这种简单的情况下,不会提供太多好处。
我强烈建议不要进行任何反射黑客攻击,因为它们首先会使使用不可变类型的大部分好处失效。不要给我一个看起来不可变的类型,但随后会以某种方式偷偷改变值 - 这会破坏用户的期望并隐藏竞争条件的风险。