增量代码的设计模式
Design pattern for incremental code
根据业务逻辑,其中一个方法的输出用作另一个方法的输入。逻辑具有线性流程。
为了模拟这种行为,现在有一个控制器class,它拥有一切。
很乱,loc太多,不好修改。异常处理也非常复杂。个别方法做了一些处理,但全局异常冒泡,涉及很多 try
catch
语句。
是否存在解决此问题的设计模式?
示例控制器Class代码
try{
Logic1Inputs logic1_inputs = new Logic1Inputs( ...<some other params>... );
Logic1 l = new Logic1(logic1_inputs);
try{
Logic1Output l1Output = l.execute();
} catch( Logic1Exception l1Exception) {
// exception handling
}
Logic2Inputs logic2_inputs = new Logic2Inputs(l1Output);
Logic2 l2 = new Logic2(logic2_inputs);
try{
Logic2Output l2Output = l2.execute();
} catch( Logic2Exception l2Exception) {
// exception handling
}
Logic3Inputs logic3_inputs = new Logic3Inputs(l1Output, l2Output);
Logic3 l3 = new Logic3(logic2_inputs);
try{
Logic3Output l3Output = l3.execute();
} catch( Logic3Exception l3Exception) {
// exception handling
}
} catch(GlobalException globalEx){
// exception handling
}
我认为这称为管道:http://en.wikipedia.org/wiki/Pipeline_%28software%29此模式用于数据流经一系列任务或阶段的算法。
您可以搜索执行此操作的库 (http://code.google.com/p/pipelinepattern) 或尝试您自己的 java 实现
基本上,您将所有对象都放在一个列表中,并将一个 si 的输出传递给下一个 si。这是一个天真的实现,但你可以添加泛型和你需要的一切
public class BasicPipelinePattern {
List<Filter> filters;
public Object process(Object input) {
for (Filter c : filters) {
try {
input = c.apply(input);
} catch (Exception e) {
// exception handling
}
}
return input;
}
}
public interface Filter {
public Object apply(Object o);
}
当遇到这样的问题时,我喜欢看看其他编程语言如何解决它。然后我可能会借用这个概念并将其应用到我正在使用的语言中。
在 javascript 中,有很多关于承诺的讨论,以及它们如何不仅可以简化异步处理,还可以简化错误处理。 This page 很好地介绍了这个问题。
然后使用 "thenables" 调用了方法。这是伪代码:
initialStep.execute().then(function(result1){
return step2(result1);
}).then(function(result2){
return step3(result3);
}).error(function(error){
handle(error);
}).done(function(result3){
handleResult(result3)
});
此模式的优点是您可以专注于处理并在一处有效地处理错误,而无需担心每一步都检查是否成功。
那么这在 java 中如何运作?我会看看 promises/futures 个库之一,也许 jdeferred。我希望你能把这样的东西放在一起(为简洁起见,假设 java 8):
initialPromise.then( result1 -> {
Logic2 logic2 = new Logic2(new Logic2Inputs(result1));
return logic2.execute();
}).then(result2 -> {
Logic3 logic3 = new Logic3(new Logic3Inputs(result2));
return logic2.execute();
}).catch(exception -> {
handleException(exception)
}).finally( result -> {
handleResult(result);
});
这当然掩盖了代码中隐藏的要求。您提到在第 3 步中您需要第 1 步 和 第 2 步的输出。如果您正在编写 scala,则语法糖可以为您处理这个问题(省略错误处理那一刻):
for(result1 <- initialStep.execute();
Logic2 logic2 = new Logic2(Logic2Input(result1));
result2 <- logic2.execute();
Logic3 logic3 = new Logic3(Logic3Input(result1, result2));
result3 <- logic3.execute()) yield result3;
但是既然你没有这方面的能力,那么你只能选择重构每个步骤以仅采用上一步的输出,或者嵌套处理以便 result1 仍然在范围内您需要设置第 3 步。
正如@user1121883 提到的那样,经典的替代方法是使用流水线处理器。这种方法的缺点是,如果您的输入和输出是同一类型,它的效果最好。否则,您将不得不到处使用 Object 并进行大量类型检查。
另一种选择是为管道公开 fluent interface。同样,您想要进行一些重构,也许是为了拥有一个无参数的构造函数和一个一致的输入和输出接口:
Pipeline p = new Pipeline();
p.then(new Logic1())
.then(new Logic2())
.then(new Logic3())
.addErrorHandlder(e->handleError(e))
.complete();
最后一个选项更理想化java,但保留了 thenables 处理的许多优点,所以这可能是我要采用的方式。
根据业务逻辑,其中一个方法的输出用作另一个方法的输入。逻辑具有线性流程。 为了模拟这种行为,现在有一个控制器class,它拥有一切。
很乱,loc太多,不好修改。异常处理也非常复杂。个别方法做了一些处理,但全局异常冒泡,涉及很多 try
catch
语句。
是否存在解决此问题的设计模式?
示例控制器Class代码
try{
Logic1Inputs logic1_inputs = new Logic1Inputs( ...<some other params>... );
Logic1 l = new Logic1(logic1_inputs);
try{
Logic1Output l1Output = l.execute();
} catch( Logic1Exception l1Exception) {
// exception handling
}
Logic2Inputs logic2_inputs = new Logic2Inputs(l1Output);
Logic2 l2 = new Logic2(logic2_inputs);
try{
Logic2Output l2Output = l2.execute();
} catch( Logic2Exception l2Exception) {
// exception handling
}
Logic3Inputs logic3_inputs = new Logic3Inputs(l1Output, l2Output);
Logic3 l3 = new Logic3(logic2_inputs);
try{
Logic3Output l3Output = l3.execute();
} catch( Logic3Exception l3Exception) {
// exception handling
}
} catch(GlobalException globalEx){
// exception handling
}
我认为这称为管道:http://en.wikipedia.org/wiki/Pipeline_%28software%29此模式用于数据流经一系列任务或阶段的算法。
您可以搜索执行此操作的库 (http://code.google.com/p/pipelinepattern) 或尝试您自己的 java 实现
基本上,您将所有对象都放在一个列表中,并将一个 si 的输出传递给下一个 si。这是一个天真的实现,但你可以添加泛型和你需要的一切
public class BasicPipelinePattern {
List<Filter> filters;
public Object process(Object input) {
for (Filter c : filters) {
try {
input = c.apply(input);
} catch (Exception e) {
// exception handling
}
}
return input;
}
}
public interface Filter {
public Object apply(Object o);
}
当遇到这样的问题时,我喜欢看看其他编程语言如何解决它。然后我可能会借用这个概念并将其应用到我正在使用的语言中。
在 javascript 中,有很多关于承诺的讨论,以及它们如何不仅可以简化异步处理,还可以简化错误处理。 This page 很好地介绍了这个问题。
然后使用 "thenables" 调用了方法。这是伪代码:
initialStep.execute().then(function(result1){
return step2(result1);
}).then(function(result2){
return step3(result3);
}).error(function(error){
handle(error);
}).done(function(result3){
handleResult(result3)
});
此模式的优点是您可以专注于处理并在一处有效地处理错误,而无需担心每一步都检查是否成功。
那么这在 java 中如何运作?我会看看 promises/futures 个库之一,也许 jdeferred。我希望你能把这样的东西放在一起(为简洁起见,假设 java 8):
initialPromise.then( result1 -> {
Logic2 logic2 = new Logic2(new Logic2Inputs(result1));
return logic2.execute();
}).then(result2 -> {
Logic3 logic3 = new Logic3(new Logic3Inputs(result2));
return logic2.execute();
}).catch(exception -> {
handleException(exception)
}).finally( result -> {
handleResult(result);
});
这当然掩盖了代码中隐藏的要求。您提到在第 3 步中您需要第 1 步 和 第 2 步的输出。如果您正在编写 scala,则语法糖可以为您处理这个问题(省略错误处理那一刻):
for(result1 <- initialStep.execute();
Logic2 logic2 = new Logic2(Logic2Input(result1));
result2 <- logic2.execute();
Logic3 logic3 = new Logic3(Logic3Input(result1, result2));
result3 <- logic3.execute()) yield result3;
但是既然你没有这方面的能力,那么你只能选择重构每个步骤以仅采用上一步的输出,或者嵌套处理以便 result1 仍然在范围内您需要设置第 3 步。
正如@user1121883 提到的那样,经典的替代方法是使用流水线处理器。这种方法的缺点是,如果您的输入和输出是同一类型,它的效果最好。否则,您将不得不到处使用 Object 并进行大量类型检查。
另一种选择是为管道公开 fluent interface。同样,您想要进行一些重构,也许是为了拥有一个无参数的构造函数和一个一致的输入和输出接口:
Pipeline p = new Pipeline();
p.then(new Logic1())
.then(new Logic2())
.then(new Logic3())
.addErrorHandlder(e->handleError(e))
.complete();
最后一个选项更理想化java,但保留了 thenables 处理的许多优点,所以这可能是我要采用的方式。