建议执行流水线操作的设计模式

时间:2019-11-30 06:22:19

标签: java design-patterns java-8

问题陈述: 我必须处理类似于管道的请求。
例如:
当请求到达时,它必须经历一系列操作,例如(step1,step2,step3 ...)。
因此,为了实现这一点,我使用了模板设计模式

请查看并建议我是否正确实施了此问题,或者有更好的解决方案。
我怀疑我的方法会引入代码异味,因为我经常更改对象的值。

还建议我是否可以使用Java 8来完成此任务? 谢谢。

代码:

package com.example.demo.design;

import java.util.List;

public abstract class Template {
    @Autowired
    private Step1 step1;
    @Autowired
    private Step2 step2;
    @Autowired
    private Save save;
    List<String> stepOutput = null;
    List<String> stepOutputTwo = null;
    List<String> stepOutputThree = null;

    public void step1(String action1) {
        stepOutput = step1.method(action1);
    }

    public void step2(String action2) {
        stepOutputTwo = step2.method(stepOutput, action2);
    }

    abstract public void step3();

    public void save() {
        save.persist(stepOutputThree);
    }

    final public void run(String action1, String action2) {
        step1(action1);
        step2(action2);
        stepOutputTwo = step3();
    }
}

3 个答案:

答案 0 :(得分:1)

我有同样的问题!您可以执行以下操作:uncheckCall方法用于处理异常。

final public void run(String action1, String action2) {
     //other stuffs 

     Stream.of(step1.method(action1))
           .map(stepOutput->uncheckCall(() ->step2.method(stepOutput,action2)))
           .forEach(stepOutputThree -> uncheckCall(()->save.persist(stepOutputThree)));

    //.....

}

对于uncheckCall方法:

 public static <T> T uncheckCall(Callable<T> callable) {
    try {
        return callable.call();
    } catch (RuntimeException e) {
       // throw BusinessException.wrap(e);
    } catch (Exception e) {
        //throw BusinessException.wrap(e);
    }
}

答案 1 :(得分:1)

在Java 8流模型中,可能类似于以下内容:

final public void run(String action1, String action2) {
    Stream.of(action1)                        // Stream<String>
          .map(s -> step1.method(s))          // Stream<List<String>>
          .map(l -> step2.method(l,action2)   // Stream<List<String>>
          .map(l -> step3.method(l))          // Stream<List<String>>
          .forEach(l -> save.persist(l));
}

答案 2 :(得分:0)

好吧,当存在“管道”,“操作顺序”等时,想到的第一个设计模式是“责任链”,如下所示:

Chain of Responsibility

并为您提供以下好处:

  1. 允许您在必要时(例如在运行时)添加新的处理程序,而无需修改其他处理程序和处理逻辑(SOLID的“打开/关闭原理”)
  2. 允许处理程序在必要时停止处理请求
  3. 允许您将处理程序的处理逻辑彼此分离(SOLID的单一职责原则)
  4. 允许您定义处理程序的顺序以处理处理程序本身之外的请求

现实世界用法的一个示例是Servlet filters,您在其中调用doFilter(HttpRequest, HttpResponse, FilterChain)来调用下一个处理程序

protected void doFilter(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) {
    if (haveToInvokeNextHandler) {
        chain.doFilter(req, resp);
    }
}

在使用经典责任链模式的情况下,您的处理管道可能如下所示:

API

public class StepContext {
    private Map<String, Object> attributes = new HashMap<>();

    public <T> T getAttribute(String name) {
        (T) attributes.get(name);
    }

    public void setAttribute(String name, Object value) {
        attributes.put(name, value);
    }
}

public interface Step {
    void handle(StepContext ctx);
}

public abstract class AbstractStep implements Step {
    private Step next;

    public AbstractStep() {

    }

    public AbstractStep(Step next) {
        this.next = next;
    }

    protected void next(StepContext ctx) {
        if (next != null) {
            next.handle(ctx);
        }
    }
}

实施

public class Step1 extends AbstractStep {

    public Step1(Step next) {
        super(next);
    }

    public void handle(StepContext ctx) {
        String action1 = ctx.getAttribute("action1");
        List<String> output1 = doSomething(action1);
        ctx.setAttribute("output1", output1);

        next(ctx); // invoke next step
    }
}

public class Step2 extends AbstractStep {

    public Step2(Step next) {
        super(next);
    }

    public void handle(StepContext ctx) {
        String action2 = ctx.getAttribute("action2");
        List<String> output1 = ctx.getAttribute("output1");
        List<String> output2 = doSomething(output1, action2);
        ctx.setAttribute("output2", output2);

        next(ctx); // invoke next step
    }
}

public class Step3 extends AbstractStep {

    public Step3(Step next) {
        super(next);
    }

    public void handle(StepContext ctx) {
        String action2 = ctx.getAttribute("action2");
        List<String> output2 = ctx.getAttribute("output2");
        persist(output2);

        next(ctx); // invoke next step
    }
}

客户代码

Step step3 = new Step3(null);
Step step2 = new Step2(step3);
Step step1 = new Step1(step2);

StepContext ctx = new StepContext();
ctx.setAttribute("action1", action1);
ctx.setAttribute("action2", action2);

step1.handle(ctx);

所有这些东西都可以简化为处理程序链,通过删除相应的next引用将它们相互分离,以防您的处理管道必须始终调用所有可用步骤而不控制上一个调用:

API

public class StepContext {
    private Map<String, Object> attributes = new HashMap<>();

    public <T> T getAttribute(String name) {
        (T) attributes.get(name);
    }

    public void setAttribute(String name, Object value) {
        attributes.put(name, value);
    }
}

public interface Step {
    void handle(StepContext ctx);
}

实施

public class Step1 implements Step {
    public void handle(StepContext ctx) {
        String action1 = ctx.getAttribute("action1");
        List<String> output1 = doSomething(action1);
        ctx.setAttribute("output1", output1);
    }
}

public class Step2 implements Step {
    public void handle(StepContext ctx) {
        String action2 = ctx.getAttribute("action2");
        List<String> output1 = ctx.getAttribute("output1");
        List<String> output2 = doSomething(output1, action2);
        ctx.setAttribute("output2", output2);
    }
}

public class Step3 implements Step {
    public void handle(StepContext ctx) {
        String action2 = ctx.getAttribute("action2");
        List<String> output2 = ctx.getAttribute("output2");
        persist(output2);
    }
}

客户代码

请注意,在使用Spring框架(仅注意到@Autowired注释)的情况下,可以更简化客户端代码,因为可以使用@Autowired注释将相应类型的所有bean注入到相应的集合。

documentation的内容如下:

  

自动装配数组,集合和地图

     

对于数组,Collection或Map依赖项类型,容器将自动装配与声明的值类型匹配的所有bean。为此,必须将映射键声明为String类型,它将解析为相应的bean名称。将根据目标组件的Ordered和@Order值对容器提供的此类集合进行排序,否则将遵循其在容器中的注册顺序。另外,单个匹配的目标bean也可以是一般类型的Collection或Map本身,就这样注入。

public class StepsInvoker {
    // spring will put all the steps into this collection in order they were declared
    // within the spring context (or by means of `@Order` annotation)
    @Autowired
    private List<Step> steps;

    public void invoke(String action1, String action2) {
        StepContext ctx = new StepContext();
        ctx.setAttribute("action1", action1);
        ctx.setAttribute("action2", action2);

        steps.forEach(step -> step.handle(ctx))
    }
}
相关问题