问题陈述:
我必须处理类似于管道的请求。
例如:
当请求到达时,它必须经历一系列操作,例如(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();
}
}
答案 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)
好吧,当存在“管道”,“操作顺序”等时,想到的第一个设计模式是“责任链”,如下所示:
并为您提供以下好处:
现实世界用法的一个示例是Servlet filters,您在其中调用doFilter(HttpRequest, HttpResponse, FilterChain)
来调用下一个处理程序
protected void doFilter(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) {
if (haveToInvokeNextHandler) {
chain.doFilter(req, resp);
}
}
在使用经典责任链模式的情况下,您的处理管道可能如下所示:
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
引用将它们相互分离,以防您的处理管道必须始终调用所有可用步骤而不控制上一个调用:
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))
}
}