首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >没有公共接口的步骤序列的模式

没有公共接口的步骤序列的模式
EN

Stack Overflow用户
提问于 2014-10-08 06:16:37
回答 3查看 3.8K关注 0票数 9

在我的java应用程序中,我得到了一个方法,该方法运行一长串步骤(同步),其中一个步骤的结果是下一个步骤的输入。

例如:

代码语言:javascript
运行
复制
// 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-否则块中编写了这一系列步骤。由于每个步骤都有不同的签名,因此没有公共接口。我一直在研究一些不同的模式,并尝试自定义模式,如责任链命令,但没有得到满意的结果。

我想知道这个丑陋的、冗长的、如果-否则的部分是否是要走的路,还是有一种模式可以帮助使这一系列步骤更加干净和可伸缩。

EN

回答 3

Stack Overflow用户

发布于 2014-10-08 07:21:11

您必须自己回答的一个问题是,为什么我要重构我的代码?

你想让它成为

  • 更干净的密码?
  • 更模块化?
  • 这些步骤在运行时必须是可配置的(可替换的)吗?

重构以使代码清除

如果不需要在运行时配置这些步骤,并且希望使代码比您应该看到的注释更干净。每个评论都是一个提示。

将代码块分解为方法,并按步骤命名它们

代码语言:javascript
运行
复制
/**
 * 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。因此,不再需要内联评论了。最终,您可以给该方法更好的名称,并完全省略javadoc。

重构,以便使这些步骤在运行时中可替换

如果您想配置在运行时执行的步骤(例如,由于某些用户输入),则必须将它们封装在对象中,因为您的应用程序对可以替换的对象的引用。

因为您希望所有的步骤都有一个通用的api,所以必须使它更加通用。

从客户的角度开始思考。如何执行这些步骤。例如。

代码语言:javascript
运行
复制
for (Step step : steps) {
    boolean executeNext = step.execute();
    if (!executeNext) {
        break;
    }
}

设计一个Step接口

代码语言:javascript
运行
复制
public interface Step {
    boolean execute();
}

如何将一个步骤的输出作为另一个步骤的输入传递给另一个步骤?

建立一个接口

代码语言:javascript
运行
复制
public static interface StepInput<T> {
    public T getInput();
}

执行你的步骤。一个抽象的课程会帮助你。

代码语言:javascript
运行
复制
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;
    }
}

在运行时配置这些步骤并执行

代码语言:javascript
运行
复制
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;
    }
}
票数 11
EN

Stack Overflow用户

发布于 2014-10-08 06:44:18

这个场景-where --您做了很多事情,如果其中任何一个失败,都希望中止和记录--这就是设计异常处理的目的。例如:

代码语言:javascript
运行
复制
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.createObjectsMapanotherService.createAnotherObject会抛出它们自己的异常,而不是让您检查返回值。那你只需要写:

代码语言:javascript
运行
复制
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 )

票数 0
EN

Stack Overflow用户

发布于 2014-10-08 10:32:18

选项:

  1. Memento模式:使用memento,您可以存储对象的状态。就像你想重做和撤销的时候。这样,当您在步骤1和步骤3中有类似的方法时,您可以简单地使用1通用方法。然后,使用撤销和重做,您知道您必须保存您的状态。想一想节省步数的可能性。
  2. 策略模式:使用策略模式,您将保存IF-ELSE语句。您只需转到一个函数,策略对象将决定其余的。将路由器视为策略类。路由器将从多个进程选项中确定最佳方式、最佳路由或最佳进程。
  3. 观察者模式:这有点像MVC。我一直认为那个观察者是个闭路电视。当事情发生变化时,有些奇怪的事情发生了,中央电视台的管理员会知道的。因此,您有一个控制器类,它监视一切,并配置下一步要去的位置。

谢谢,

票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26250321

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档