Java 更改遗留代码中的不可变类

Java 更改遗留代码中的不可变类,java,immutability,Java,Immutability,我想替换(可变)类 使用不可变类 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 NewValue { private fin

我想替换(可变)类

使用不可变类

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 NewValue {
  private final int value;
  
  public NewValue(int value) { this.value = value; }
  
  public int getValue() { return value; }
  
  /* no setter, obviously */
}
在代码的大部分部分,类似于
newValue.set(777)
的内容可以被
newValue=newnewvalue(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());
  }
}
class EvilSetter {

  public static void evilSet(NewValue newValue, int x) {
    // temporarily make newValue.value both public and non-final, set it to x
  }
}
这些遗留部件很难更改,我们希望尽可能少地进行调整。有没有办法编写某种“邪恶”的setter方法,可以在遗留代码中使用?差不多

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());
  }
}
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);
    }

}
清楚地记录这些代码只应用于与遗留代码的接口,并根据需要标记为已弃用。这显然并不理想,但这适用于整个情况

如果类更复杂(例如,也有一些具有非平凡行为的方法),那么通过包装
NewValue
的实例来实现
OldValue
可能是值得的,但在这种简单的情况下,这不会带来太多好处



我强烈建议不要使用任何反射黑客,因为它们首先会使使用不可变类型的大部分好处失效。不要给我一个看起来不可变的类型,但是,然后以某种方式偷偷地更改值-这打破了用户的期望并隐藏了竞争条件的风险。

您可以通过更改私有成员的值。或者尝试在您的不可变类型周围为遗留代码提供一些可变包装。或者让类可变,并将setter标记为
@Deprecated
@jeroensteenbeek根据JavaBeans规范,这不是setter。这是一种名称不正确的工厂方法。@Jeroensteenbeek在我看来,这是一个非常不适合该方法的名称,在这里它永远不会通过代码审查。