Java 流水线设计模式的实现
这是一个关于管道实现的设计问题。下面是我天真的实现 管道中各个步骤/阶段的接口:Java 流水线设计模式的实现,java,oop,design-patterns,design-principles,java-8,Java,Oop,Design Patterns,Design Principles,Java 8,这是一个关于管道实现的设计问题。下面是我天真的实现 管道中各个步骤/阶段的接口: public interface Step<T, U> { public U execute(T input); } public class StepOne implements Step<Integer, Integer> { @Override public Integer execute(Integer input) { return inp
public interface Step<T, U> {
public U execute(T input);
}
public class StepOne implements Step<Integer, Integer> {
@Override
public Integer execute(Integer input) {
return input + 100;
}
}
public class StepTwo implements Step<Integer, Integer> {
@Override
public Integer execute(Integer input) {
return input + 500;
}
}
public class StepThree implements Step<Integer, String> {
@Override
public String execute(Integer input) {
return "The final amount is " + input;
}
}
public class Main {
public static void main(String[] args) {
Pipeline pipeline = new Pipeline();
pipeline.addStep(new StepOne());
pipeline.addStep(new StepTwo());
pipeline.addStep(new StepThree());
pipeline.execute();
}
}
但是,正如您所看到的,Naiver实现有许多局限性
其中一个主要问题是,由于需求是每个步骤的输出可以是任何类型,所以朴素的实现不是类型安全的(管道类中的execute方法)。如果我碰巧将管道中的步骤连接错误,应用程序将失败
有谁能帮我设计解决方案,添加到我已经编写的代码中,或者给我指出一个已经存在的模式来解决这个问题吗?我将重点介绍
如果我碰巧将管道中的步骤连接错误,应用程序将失败
是的,这是个问题<代码>第三步是这里的陌生人。我不认为一个简单的模式可能有用,我确实认为它必须是策略和构建器模式的组合。例如:
Pipeline<Integer,Integer> intPipe = new Pipeline<>();
intPipe = intPipe.add(new StepOne()); // increment 100
intPipe = intPipe.add(new StepTwo()); // increment 500
Pipeline<String, Integer> strPipe = intPipe.add(new StepThree()); // convert
Step<Integer, String> source = Step.of(Object::toString);
Step<Integer, Integer> toHex = source.pipe(it -> Integer.parseInt(it, 16));
toHex.execute(11/*0x11*/);// return 17;
Pipeline intPipe=新管道();
intPipe=intPipe.add(新的StepOne());//增量100
intPipe=intPipe.add(新的第二步());//增量500
管道strPipe=intPipe.add(新的StepThree());//转换
管道是这样的:
public static class Pipeline<IN, OUT> {
//...
public<A> Pipeline<OUT,A> add(Step<IN,A> step) {
pipelineSteps.add(step);
return (Pipeline<OUT,A>)this;
}
}
public class Pipeline {
private List<Step> pipelineSteps = new ArrayList<>();
private Object firstStepInput = 100;
public Pipeline() {
pipelineSteps.add(new StepOne());
pipelineSteps.add(new StepTwo());
pipelineSteps.add(new StepThree());
}
public void execute() {
for (Step step : pipelineSteps) {
Object out = step.execute(firstStepInput);
firstStepInput = out;
}
}
public String getResult() {
return (String) firstStepInput;
}
}
公共静态类管道{
//...
公共管道添加(步骤){
管道步骤。添加(步骤);
返回(管道)这个;
}
}
使用fast builder语法,这可能会起作用:
Pipeline<String, Integer> pipe = new Pipeline<Integer, Integer>()
.add(new StepOne()).add(new StepTwo()).add(new StepThree());
管道=新管道()
.add(新步骤一()).add(新步骤二()).add(新步骤三());
这应该是可行的,因为泛型不是字节码的一部分。您的方法非常好。但是,我会这样编写管道类:
public static class Pipeline<IN, OUT> {
//...
public<A> Pipeline<OUT,A> add(Step<IN,A> step) {
pipelineSteps.add(step);
return (Pipeline<OUT,A>)this;
}
}
public class Pipeline {
private List<Step> pipelineSteps = new ArrayList<>();
private Object firstStepInput = 100;
public Pipeline() {
pipelineSteps.add(new StepOne());
pipelineSteps.add(new StepTwo());
pipelineSteps.add(new StepThree());
}
public void execute() {
for (Step step : pipelineSteps) {
Object out = step.execute(firstStepInput);
firstStepInput = out;
}
}
public String getResult() {
return (String) firstStepInput;
}
}
公共类管道{
private List pipelineSteps=new ArrayList();
私有对象firstStepInput=100;
公共管道(){
添加(新的StepOne());
添加(新的步骤二());
添加(新的StepThree());
}
public void execute(){
用于(步骤:pipelineSteps){
对象输出=步骤执行(第一步输入);
第一步输入=输出;
}
}
公共字符串getResult(){
返回(字符串)第一步输入;
}
}
这样,所有特定的步骤知识都封装在管道类中
在这种情况下,execute方法可以执行循环。但是,如果需要,execute类可以逐个执行这些步骤。为什么需要额外的
管道类?我想你可以除掉中间人。这将使api更简单,例如:
Pipeline<Integer,Integer> intPipe = new Pipeline<>();
intPipe = intPipe.add(new StepOne()); // increment 100
intPipe = intPipe.add(new StepTwo()); // increment 500
Pipeline<String, Integer> strPipe = intPipe.add(new StepThree()); // convert
Step<Integer, String> source = Step.of(Object::toString);
Step<Integer, Integer> toHex = source.pipe(it -> Integer.parseInt(it, 16));
toHex.execute(11/*0x11*/);// return 17;
Step source=Step.of(Object::toString);
步骤toHex=source.pipe(it->Integer.parseInt(it,16));
toHex.execute(11/*0x11*/);//返回17;
您可以按如下方式简单地实现管道模式:
interface Step<I, O> {
O execute(I value);
default <R> Step<I, R> pipe(Step<O, R> source) {
return value -> source.execute(execute(value));
}
static <I, O> Step<I, O> of(Step<I, O> source) {
return source;
}
}
接口步骤{
O执行(I值);
默认阶梯管道(阶梯源){
返回值->source.execute(执行(值));
}
静态步进(步进源){
返回源;
}
}
在以前的java版本中,您可以使用抽象类:
abstract static class Step<I, O> {
public abstract O execute(I value);
public <R> Step<I, R> pipe(Step<O, R> source) {
return new Step<I, R>() {
@Override
public R execute(I value) {
return source.execute(Step.this.execute(value));
}
};
}
public static <I, O> Step<I, O> of(Step<I, O> source) {
return source;
}
}
抽象静态类步骤{
公开摘要O执行(I值);
公用阶梯管道(阶梯源){
返回新步骤(){
@凌驾
公共R执行(I值){
返回source.execute(Step.this.execute(value));
}
};
}
公共静态步骤(步骤源){
返回源;
}
}
您基本上可以使用公共类管道{
private List pipelineSteps=new ArrayList();
私有对象firstStepInput=100;
公共管道(){
添加(新的StepOne());
添加(新的步骤二());
添加(新的StepThree());
}
您不需要为此创建新接口
Java8已经有一个名为Function的函数接口,它允许您创建函数链(换句话说,您的管道)
Function addOne=it->{
系统输出打印项次(it+1);
返回+1;
};
函数addTwo=it->{
系统输出打印项次(it+2);
返回+2;
};
功能时间2=输入->{
系统输出打印项次(输入*2);
返回输入*2;
};
最终功能管道=添加一个
.第二次(第二次)
.第二(加两);
管道。应用(10);
如果你想更多地了解函数接口:
指向引用模式的链接。谢谢@ NekBeor指向论文。然而,通过本文,我无法理解流水线是如何设计的,以便它可以处理不同输出类型的阶段/步骤。/对于您所述的示例。请参见此处,感谢Nick提供的链接。此处提供的示例帮助很大。@NickBell链接已关闭感谢您指出如何正确封装管道类。感谢Peter回答问题!:)@PrashantChauhan随时为您服务;DBy decents,低估的答案!这是amazing、 你能解释一下Step.of(Object::toString)
是如何工作的吗?toString
是如何被解释为Step
?刚刚在一个应用程序中实现了这一点,代码很少,但效果很好。@z0r:它与Step.of(input->input.toString())是一样的;
。:
运算符是引用类的方法的lambda表达式。请格式化(编写答案时有一个预览窗口)解释你的答案(&D)。你确实想让人们理解你做了什么,不是吗?我们可以在算法中也有一个抽象方法,并强制用户实现该方法。例如:抽象函数userDefined;final Function pipe=sourceInt.and then(userDefined)。and()…投票赞成使用内置interfa