我想要一些关于我碰到的技术的建议。通过查看代码片段可以很容易地理解,但是我将在以下段落中进一步说明。
使用“代码三明治”成语是处理资源管理的常见问题。用于C的RAII成语,我切换到Java,发现我的异常安全的资源管理导致深入的嵌套代码,其中我很难掌握常规控制流程。
我尝试了不同的解决方案来应对这个问题:
>明确维护程序状态:resource1aquired,fileopened …,并有条件地清理:if(resource1acquired)resource1.cleanup()…但是我在显式变量中复制程序状态 – 运行时知道状态,而我不想关心它。
>在函数中包装每个嵌套块 – 导致更难以跟随控制流,并使真正尴尬的函数名称:runResource1Acquired(r1),runFileOpened(r1,file),…
而不是这样:
// (pseudocode)
try {
connection = DBusConnection.SessionBus(); // may throw, needs cleanup
try {
exported = false;
connection.export("/MyObject", myObject ); // may throw, needs cleanup
exported = true;
//... more try{}finally{} nested blocks
} finally {
if( exported ) connection.unExport( "/MyObject" );
}
} finally {
if (connection != null ) connection.disconnect();
}
使用辅助构造,您可能会得到一个更线性的构造,其中补偿代码就位于发起者旁边。
class Compensation {
public void compensate(){};
}
compensations = new Stack();
而嵌套代码变成线性的:
try {
connection = DBusConnection.SessionBus(); // may throw, needs cleanup
compensations.push( new Compensation(){ public void compensate() {
connection.disconnect();
});
connection.export("/MyObject", myObject ); // may throw, needs cleanup
compensations.push( new Compensation(){ public void compensate() {
connection.unExport( "/MyObject" );
});
// unfolded try{}finally{} code
} finally {
while( !compensations.empty() )
compensations.pop().compensate();
}
我很高兴:无论有多少异常路径,控制流程保持线性,清理代码在视觉上与始发代码相邻。除此之外,它不需要人为限制的CloseQuietly方法,这使得它更加灵活(即不仅可关闭对象,而且还可以断开连接,可回滚以及任何其他方式)。
但…
我在其他地方没有发现这种技术。所以这里的问题是:
这种技术是否有效?你看到什么bug?
非常感谢。