在我的java应用程序中,我得到了一个运行一系列步骤(同步)的方法,其中一步结果是下一步的输入。
例如:
// Step 1
Map<String, SomeObject> objectsMap = someService.createObjectsMap();
if (!objectsMap.isEmpty()) {
// Step 2
AnotherObject anotherObject = anotherService.createAnotherObject(objectsMap);
if (null != anotherObject) {
// Step 3 that gets anotherObject as input and returns something else
} else { // Step 2 failed
// log and handle
}
} else { // Step 1 failed
// log and handle
}
所以我在一系列if-else块中编写了这一系列步骤。 由于每个步骤具有不同的签名,因此步骤没有通用接口。我一直在讨论一些不同的问题,并尝试自定义chain-of-responsibility和command等模式,但无法获得满意的结果。
我想知道这个丑陋的长if-else部分是否可行,或者是否有一个模式可以帮助使这一系列步骤更加干净和可扩展。
答案 0 :(得分:5)
你必须回答的一个问题是为什么我要重构我的代码?
你想要它
吗?重构以使代码清洁
如果不需要在运行时配置这些步骤,并且您希望使代码更干净,那么您应该查看您所做的注释。每条评论都是一个提示。
将代码块分解为方法,并在步骤
之后命名它们/**
* Explain what step1 does.
*/
private void step1() {
// Step 1
Map<String, SomeObject> objectsMap = someService.createObjectsMap();
if (!objectsMap.isEmpty()) {
step2(objectsMap);
} else { // Step 1 failed
// log and handle
}
}
/**
* Explain what step2 does.
*/
private void step2(Map<String, SomeObject> objectsMap) {
// Step 2
final AnotherObject anotherObject = anotherService
.createAnotherObject(objectsMap);
if (null != anotherObject) {
step3(anotherObject);
} else { // Step 2 failed
// log and handle
}
}
/**
* Explain what step3 does.
*/
private void step3(AnotherObject anotherObject) {
// Step 3 that gets anotherObject as input and returns something
// else
}
这种方法只是将方法分解为更小的方法。优点是每个较小的方法只负责一件事。因为它是一种方法,你可以添加javadoc。所以不再需要内联评论了。
重构以使步骤在运行时可替换
如果要配置在运行时执行的步骤(例如,由于某些用户输入),则必须将它们封装在对象中,因为应用程序引用了可以替换的对象。
由于你希望所有步骤都有一个共同的api,你必须使它更通用。
从客户的角度开始思考。应该如何执行这些步骤。例如。
for (Step step : steps) {
boolean executeNext = step.execute();
if (!executeNext) {
break;
}
}
设计步骤界面
public interface Step {
boolean execute();
}
如何将一步的输出作为输入传递给另一步?
制作界面
public static interface StepInput<T> {
public T getInput();
}
实施您的步骤。抽象课会帮助你。
public abstract class InputOutputStep<T> implements Step,
StepInput<T> {
private T returnValue;
protected void setReturnValue(T returnValue) {
this.returnValue = returnValue;
}
public T getInput() {
return returnValue;
}
}
public class Step1 extends InputOutputStep<Map<String, SomeObject>> {
private StepInput<Map<String, SomeObject>> stepInput;
public Step1(StepInput<Map<String, SomeObject>> stepInput) {
this.stepInput = stepInput;
}
public boolean execute() {
boolean executeNext = false;
Map<String, SomeObject> objectsMap = stepInput.getInput();
if (!objectsMap.isEmpty()) {
// Step 2
setReturnValue(objectsMap);
executeNext = true;
} else { // Step 1 failed
// log and handle
}
return executeNext;
}
}
public class Step2 extends InputOutputStep<AnotherObject> {
private StepInput<Map<String, SomeObject>> stepInput;
private AnotherService anotherService;
public Step2(AnotherService anotherService,
StepInput<Map<String, SomeObject>> stepInput) {
this.anotherService = anotherService;
this.stepInput = stepInput;
}
public boolean execute() {
boolean executeNext = false;
Map<String, SomeObject> objectsMap = stepInput.getInput();
AnotherObject anotherObject = anotherService
.createAnotherObject(objectsMap);
if (null != anotherObject) {
setReturnValue(anotherObject);
executeNext = true;
} else { // Step 2 failed
// log and handle
}
return executeNext;
}
}
public class Step3 extends InputOutputStep<Void> {
private StepInput<AnotherObject> stepInput;
public Step3(StepInput<AnotherObject> stepInput) {
this.stepInput = stepInput;
}
public boolean execute() {
AnotherObject anotherObject = stepInput.getInput();
setReturnValue(null);
return false;
}
}
在运行时配置步骤并执行
Step1 step1 = new Step1(stepInput);
Step2 step2 = new Step2(anotherService, step1);
Step step3 = new Step3(step2);
Step[] steps = new Step[]{step1, step2, step3};
for (Step step : steps) {
boolean executeNext = step.execute();
if (!executeNext) {
break;
}
}
答案 1 :(得分:0)
这种情况 - 你做了很多事情,想要中止并记录任何一个失败 - 是异常处理的目的。例如:
try {
// Step 1
Map<String, SomeObject> objectsMap = someService.createObjectsMap();
if (objectsMap.isEmpty())
throw new SomethingWentWrongException("Failed to get object map from service");
// Step 2
AnotherObject anotherObject = anotherService.createAnotherObject(objectsMap);
if(anotherObject == null)
throw new SomethingWentWrongException("Failed to create another object");
// Step 3 that gets anotherObject as input and returns something else
} catch(SomethingWentWrongException e) {
// log and handle
e.printStackTrace();
}
理想情况下,someService.createObjectsMap
和anotherService.createAnotherObject
会抛出自己的异常,而不是让您检查返回值。然后你只需要写:
try {
Map<String, SomeObject> objectsMap = someService.createObjectsMap();
AnotherObject anotherObject = anotherService.createAnotherObject(objectsMap);
// Step 3 that gets anotherObject as input and returns something else
} catch(Exception e) {
// log and handle
e.printStackTrace();
}
(但请注意,如果您真的想要捕捉所有失败,那么您应该只捕获Exception
答案 2 :(得分:-1)
选项:
纪念品图案: 使用memento,您可以存储对象的状态。就像你想要重做和撤消一样。 这样,当您在步骤1和步骤3中有类似的方法时,您可以简单地使用1种通用方法。 然后,使用撤消和重做,您知道必须保存您的状态。 考虑保存步骤编号的可能性。
策略模式: 使用策略模式,您将保存IF-ELSE语句。 你只需要去一个功能,战略对象将决定其余的。 将路由器视为策略类。 路由器将确定最佳方式,最佳路由或最佳流程(来自多个流程选项)。
观察者模式: 这就像MVC。 我一直认为观察者是CCTV。 当一些事情发生变化,一些奇怪的事情发生时,央视管理员就会知道。 所以你有一个控制器类,它监视所有内容,并配置你必须去的地方。
谢谢,