美文网首页
实现一个StepChain小功能

实现一个StepChain小功能

作者: 肚皮怪_Sun | 来源:发表于2019-04-23 15:28 被阅读0次

前段时间一直在做个自助机项目,功能类似与火车站的自动售票机。不过我们做自助机是给酒店用的,替代前台的功能让旅客自己操作完成酒店入住这一过程,其中涉及到一个很核心的功能——自动发放房卡。也就是通过操作自助机自动出卡,而这一过程其中就包含一系列的步骤——发卡器准备、放卡(把卡移到卡槽)、读卡(读入房卡信息)、出卡、取卡。

当时看到这个功能时也是一头包,咋这么麻烦。怎么交差,怎么实现,怎么优雅的实现,总不会用万能的if/else嵌套吧,这代码不会爆炸。


冷静过后理智告诉我,先把功能梳理清晰,把问题抽离出来。不管怎么样的需求,多看多想,总能找到一个好方法实现。接下来我把功能梳理一遍,并画了一个简单流程图。


这不就是我们需要的实现的功能嘛,流程开始接着执行步骤一、步骤二、步骤三...直到完成,如果其中任意步骤失败就会结束整个过程。到这里我脑子里已经有了大概思路,怎么实现这个功能了。

停三分钟想想,是你的话你会怎么实现。。。

好了接下来就开始编码吧
首先实现一个接口,在这里面需要做几件事情。

  • 执行当前任务
  • 记录当前是步骤
public interface IStep {
    /**
     *  执行当前步骤 
     * @param caller 调用者上一步
     * @param stepChain
     * @param context
     */
    void process(IStep caller,StepChain stepChain,StepContext context);
    /**
     * 记录当前步骤
     * @param order
     */
    void setOrder(int order);

    /**
     * 获取当前步骤
     * @return
     */
    int getOrder();
}

然后把每个步骤中需要的公共内容抽离出来,具体的实现只需要继承OrderStep即可

public abstract class OrderStep implements IStep{
    private int order=0;

    @Override
    public void setOrder(int order) {
        this.order=order;
    }

    @Override
    public int getOrder() {
        return this.order;
    }
}

接下来就是最关键部分,如何控制这些步骤有序的运行下去
我们需要在StepChain中通过一个集合保存Step1、Step2、Step3...,然后并设置每个步骤当前的顺序。

public class StepChain implements IStep {
    private int addIndex = 0;
    private List<IStep> steps = new ArrayList<>();
    private int index = 0;

    public void addStep(IStep iStep) {
        steps.add(iStep);
        iStep.setOrder(addIndex++);
    }
    ...
}

在process中处理执行逻辑:如果index等于steps.size说明已经运行到最后一步,则直接结束。否则让当前步骤继续执行下去。
具体实现如下:

public class StepChain implements IStep {
    private int addIndex = 0;
    private List<IStep> steps = new ArrayList<>();
    private int index = 0;

    public void addStep(IStep iStep) {
        steps.add(iStep);
        iStep.setOrder(addIndex++);
    }

    @Override
    public void process(IStep caller, StepChain stepChain, StepContext context) {
        if (index == steps.size()) return;
        IStep iStep = steps.get(index);
        if (caller != null && iStep.getOrder() <= caller.getOrder()) return;
        index++;
        iStep.process(caller, stepChain, context);
        
    }
    ...
}

到这里主要的功能已经完成了,接下来测试一下我们的劳动成果吧。
那实现几个具体的步骤FirstStep、SecStep、ThirdStep、FinishStep

public class FirstStep extends OrderStep {
    @Override
    public void process(IStep caller, StepChain stepChain,StepContext context) {
        System.out.println(System.currentTimeMillis()+" :执行第一步");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        stepChain.process(this,stepChain,context);//执行下一步
    }
}
public class FinishStep extends OrderStep {
    @Override
    public void process(IStep caller, StepChain stepChain, StepContext context) {
        System.out.println(System.currentTimeMillis()+"完成");
    }
}

SecStep、ThirdStep的实现内容和FirstStep基本一样,我就不贴出来。
最后看一下如何使用StepChain来控制流程。
实现如下:

public class StepMain {
    public static void main(String[] args) {
        StepChain stepChain = new StepChain();
        StepContext context = new StepContext();
        stepChain.addStep(new FirstStep());
        stepChain.addStep(new SecStep());
        stepChain.addStep(new ThirdStep());
        stepChain.addStep(new FinishStep());
        stepChain.process(null,stepChain,context);
    }
}

运行后的结果


image.png

现在已经可以按照顺序执行每个步骤,但还有一个小缺陷——如果其中某个步骤因为某种原因失败,这时候整个流程应该直接中断完成,这样才更符合具体的需求。这时候我们又要回到StepChain的process方法中。对当前的步骤进行判断,如果已中断则直接执行finish的步骤,否则正常继续下去执行。
具体实现如下:

public class StepContext {
    private boolean isFinish=false;
    public boolean isFinish() {
        return isFinish;
    }
    public void setFinish(boolean finish) {
        isFinish = finish;
    }
}

修改StepChain的process方法

  @Override
    public void process(IStep caller, StepChain stepChain, StepContext context) {
        if (context.isFinish()) {
             index = steps.size()-1;
            steps.get(index).process(caller,stepChain,context);
        } else {
            if (index == steps.size()) return;
            IStep iStep = steps.get(index);
            if (caller != null && iStep.getOrder() <= caller.getOrder()) return;
            index++;
            iStep.process(caller, stepChain, context);
        }
    }

这是时候只需在需要中断的步骤里要设置stepContex.setFinish(true)即可

public class FirstStep extends OrderStep {
    @Override
    public void process(IStep caller, StepChain stepChain,StepContext context) {
        System.out.println(System.currentTimeMillis()+" :执行第一步");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        context.setFinish(true);
        stepChain.process(this,stepChain,context);
    }
}

我们在步骤一做了修改,按原先的假设如果成立,则控制台只会打印步骤一的日志和结束日志。

运行一下main方法看一下结果:

image.png

在很多开源的框架中也有类似的设计,比如OkHttp最核心也是最优雅的一部分——Interceptor,它把请求、缓存、桥接等各个功能都解耦成一个个的Interceptor,然后用一条责任链完美地串联在一起。
到这里StepChain这个小功能就完成了....需要源码的朋友戳这里https://github.com/wds1204/StepChain


风后面是风,天空上面是天空,而你的生活可以与众不同

相关文章

网友评论

      本文标题:实现一个StepChain小功能

      本文链接:https://www.haomeiwen.com/subject/tidugqtx.html