Java 中断外部API调用的模式?
我正试着将我的思想集中在如何着手实现这个特定问题上。我们有一个执行某些逻辑并返回该逻辑结果的外部API。不幸的是,API返回一个新对象作为结果,而不仅仅是我感兴趣的部分。例如,代码如下所示:Java 中断外部API调用的模式?,java,design-patterns,Java,Design Patterns,我正试着将我的思想集中在如何着手实现这个特定问题上。我们有一个执行某些逻辑并返回该逻辑结果的外部API。不幸的是,API返回一个新对象作为结果,而不仅仅是我感兴趣的部分。例如,代码如下所示: public class ComplexObject { //lots of fields } public interface LogicApplier { LogicResult applyLogic(ComplexObject obj); } public class LogicR
public class ComplexObject {
//lots of fields
}
public interface LogicApplier {
LogicResult applyLogic(ComplexObject obj);
}
public class LogicResult {
ComplexObject result;
public ComplexObject getResult();
}
public class FirstImplementation {
private LogicApplier _applier;
public Implementation(LogicApplier applier) {
_applier = applier;
}
public ComplexObject mainImplementation (ComplexObject apply) {
LogicResult logicResult = _applier.applyLogic(apply);
ComplexObject newComplexObject = logicResult.getResult();
//Do some other stuff with new ComplexObject
}
}
所以问题是:限制LogicApplier对FirstImplementation的“权力”的最佳方式是什么?例如,我们首先调用逻辑的动机是派生一个缺少的字段,比如“name”。例如,在第二个实现中,该字段可能会有所不同,该实现现在希望从LogicApplierAPI派生“街道地址”。然而,没有什么可以阻止LogicApplier更改其他字段,比如“idNumber”
通过为我们的特定实现添加一个接口和手动映射字段是否可以最好地解决这个问题?比如:
public interface SecondImplementationLogicApplier {
public String deriveAddress(ComplexObject o);
}
public class LimitedImplementationLogicApplier implements FirstImplementationLogicApplier, SecondImplementationLogicApplier {
LogicApplier _applier;
public LimitedImplementationLogicApplier(LogicApplier applier) {
_applier = applier;
}
public String deriveFirstName(ComplexObject o) {
LogicResult res = _applier.applyLogic(o);
return res.firstName;
}
public String deriveFirstName(ComplexObject o) {
LogicResult res = _applier.applyLogic(o);
return res.address;
}
}
我认为您使用
有限实现逻辑应用程序的方法是正确的。您应该保护域中的对象免受外部可能的损坏。只更新您需要的字段
看起来您的ComplexObject
是可变的。我会考虑把它隐藏在不可变的接口后面(没有任何设置或方法来改变被暴露的对象),并将不可变的接口传递到您的代码> LimeTimePrimLogLogic Apple:/Calp>中,因此它不可能改变<代码>复杂对象< /代码>。
如果您的API需要ComplexObject
类型,并且您无法更改该类型,那么为了防止变异,您可以:
选择1
创建基本ComplexObject
实例的克隆
,并将其传递到API中。返回结果后,您将在未触及的base
实例上更新所需字段。如果ComplexObject
是“本身的东西”,并且其状态的更改不会在类实例之外产生副作用,例如更改数据库或影响其他状态,那么这将很好地工作
如果ComplexObject
的突变有副作用,或者将来可能有副作用,那么这是一个真正的问题
选择2
从ComplexObject
继承一个ReadonlyComplexObject
类,并将其传递到API中。在ReadonlyComplexObject
中,您将抑制父对象的所有行为以防止修改
在我看来,这是有漏洞的,以后会产生更多的工作-如果ComplexObject
稍后将使用新属性进行扩展,您将需要对ReadonlyComplexObject
进行更改,否则仍然会发生变异。ComplexObject
是一个可变的生成类,在整个代码库中使用,这使事情复杂化了。您的建议是让LimitedImplementationLogicApplier
接受一个包装器,比如ComplexObjectWrapperForImplementationOne
(更好的名称待定),哪种方法将我们的ComplexObject
包装成只为我们期望变异的字段公开setter的东西?我更喜欢一个接口而不是ComplexObject
(你能用该接口生成它吗?),但如果不可能,包装器也会工作。如果你能将一些不可变的东西传递到你的“派生”逻辑中,你将确保你的对象保持不变。不幸的是,它不能用接口生成。此外,“派生”逻辑在这里应被视为外部API,因此我们无法控制实现。它需要一个ComplexObject
,并返回一个ComplexObject
,这很可怕。因此,我认为最好的方法是围绕ComplexObject
进行包装,只公开一些指定字段,围绕logicalapplier
进行包装,以使用这个新的ComplexObject
包装。这听起来对吗?更新了答案。我认为我的选项2
最接近你的想法。我想你不可能有一个ComplexObject
类型的包装器(这就是你的外部API想要的吧?),它的字段/方法少于ComplexObject
类型本身。我想我现在更倾向于选项1,感谢大家的集思广益。理由是:选项2需要构建一个新的包装器类来真正控制字段。。。这不是个坏主意,但可能是另一天的问题。看起来像是克隆对象,将其映射到指定的返回类型(ImplOneResultObject
或类似的类型),然后将其全部隐藏在logicalapplier
的包装器中。LogicApplier
的API对客户端调用的更改很少,并且隐藏了克隆/转换等需要。再次感谢您的帮助。