我想对我遇到的技术提出一些建议.通过查看代码片段可以很容易地理解它,但我在以下段落中对其进行了更多的记录.
使用"Code Sandwich"习惯用法是处理资源管理的常用方法.用于C++的RAII习语,我切换到Java并发现我的异常安全的资源管理导致了深层嵌套的代码,我很难掌握常规控制流.
显然(java数据访问:这是java数据访问代码的好风格,还是最终尝试太多了?,Java io丑陋的try-finally阻塞等等)我并不孤单.
我尝试了不同的解决方案来应对这个问题:
明确地维护程序状态: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();
}
Run Code Online (Sandbox Code Playgroud)
使用辅助构造,您可以得到一个更线性的构造,其中补偿代码就在发起者旁边.
class Compensation {
public void compensate(){};
}
compensations = new Stack<Compensation>();
Run Code Online (Sandbox Code Playgroud)
嵌套代码变为线性的:
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();
}
Run Code Online (Sandbox Code Playgroud)
我很高兴:无论有多少异常路径,控制流都保持线性,清理代码在视觉上紧挨着原始代码.最重要的是,它并不需要人为地控制closeQuietly方法,这使得它更灵活(即不仅Closeable对象,而且Disconnectable,Rollbackable和让别人).
但...
我发现其他地方没有提到这种技术.所以这就是问题:
这种技术有效吗?你看到了什么错误?
非常感谢.
很好。
没有什么大的抱怨,我脑子里只有一些小事情:
final为补偿做一些事情才能看到它们。也许这会阻止一些用例| 归档时间: |
|
| 查看次数: |
2010 次 |
| 最近记录: |