我有一些代码需要发送对象的副本。之所以如此,是因为调用的服务(运行时库)会修改发送的对象。万一下面的doThing
方法需要设置ImportantObj
类中的任何字段,此对象还需要公开setter。此实现有待更改,但没有合理的期望在不久的将来进行更改。我的解决方法是提供一个执行以下操作的类:
public class DangerousCallWrapper<T> implements DangerousCaller<T> {
public T doThing(T dataObject) {
T cloneOfDataObject = #Clone of dataObject
// This service modifies the cloneOfDataObject... dangerous!
Optional<T> result = service.doThing(cloneOfDataObject);
return result.orElseThrow(() -> new RuntimeException("No data object returned);
}
}
public interface DangerousCaller<T> {
/**
* Performs the functionality of the DangerousService
*/
public T doThing(T);
}
public DangerousService<T> {
public T doThing(T data) {
data.importantField = null;
data.thing = "Done!";
return data;
}
}
public static void main() {
DangerousService service = new DangerousService<ImportantObj>();
ImportantObj important = new ImportantObj().setImportantField("Password for my bank account").setThing("Undone");
service.doThing(important);
//would fail this check
assertNotNull(important.importantField);
DangerousCallWrapper wrapper = new DangerousCallWrapper<ImportantObj>();
ImportantObj important = new ImportantObj().setImportantField("Password for my bank account").setThing("Undone");
service.doThing(important);
//would not fail this check
assertNotNull(important.importantField);
}
因此该方法的第一行是我遇到的问题。这是一个泛型类型,因此我无法显式调用某些克隆实用程序,例如Jackson或类似的程序。
所以我以为我只会在方法中添加T extends Cloneable
...但是我打开了Cloneable
禁忌(https://www.artima.com/intv/bloch13.html)以外的蠕虫罐。我还读过,复制构造函数可能是处理此问题的最佳方法...但是,我不确定如何使用泛型来表示这一点。
所以我的想法是提供一个接口Copyable
来完成您期望Cloneable
要做的事情:公开一个方法copy()
,该方法将创建类的新实例。
这构成可行的方法吗?
答案 0 :(得分:1)
要解决您的问题,您需要像这样复制dataObject
的副本:
T cloneOfDataObject = dataObject.clone();
,问题是Cloneable
没有clone()
方法,因此上面的代码无法编译。
在此前提下,创建定义Copyable
方法的自己的clone()
接口是有意义的,这样您就可以利用已实现的clone()
方法(如果存在)数据对象的类。为了获得最佳效果,该接口也必须是通用的:
interface Copyable<T> {
public T clone();
}
和类型绑定:
public class DangerousCallWrapper<T extends Copyable<T>>
implements DangerousCaller<T> {