取决于多个条件的执行和操作的解决方案模式



假设有 3 个操作ops1()ops2()ops3() 个。客户端可以请求执行这 3 个的任意组合。例如

    执行
  • (1):应执行ops1()
  • 执行
  • (2):应执行ops2()
  • perform(1, 2):应该执行 ops1(),如果ops1()成功,则执行ops2()
  • perform(1, 2, 3):应该执行ops1(),如果ops1()成功,则执行ops2(),如果 ops1() 和 ops2() 成功,则执行 ops3()

这可以继续 n ops(),尽管对我来说它只有 5。

实现这一点的简单而优雅的方法是什么?这有模式吗?

你把你的操作放在一个列表中,查看要在该列表中执行的操作,如果操作失败,让操作抛出异常,怎么样?然后,执行方法可以简单地尝试按所需顺序执行所有方法,直到完成或发生异常。

所以

private List<Callable> ops;
public void perform(int... opNums) {
    try {
        for (int i : opNums) {
            ops.get(i-1).call();
        }
    }
    catch(Exception ex) {
    }
}

我看到的解决方案有点像这样:

public void perform(int... ops) {
    for(int i : ops) {
        switch(i) {
            case 1:
                //...
                // if(taskFailed) return;
                break;
            case 2:
                //...
                // if(taskFailed) return;
                break;
            case 3:
                //...
                // if(taskFailed) return;
                break;
            // so on for all 5
        }
    }
}

这只是一般的想法,没有测试语法是否完全正确。

"taskFailed"是一个伪代码。

一种方法是

  1. opsX方法和实现此方法的类定义公共接口。
  2. 定义一个enum以了解应调用此公共接口的哪个类实现。
  3. 定义一个将用作这些调用的业务流程协调程序的类。

此设计的实现可能是

interface CommonOps {
    boolean ops();
}
class Ops1 implements CommonOps {
    @Override
    public boolean ops() {
        //...
    }
}
class Ops2 implements CommonOps {
    @Override
    public boolean ops() {
        //...
    }
}
//and on...
enum OpsOrder {
    OPS1,
    OPS2,
    OPS3
    //... and on
    ;
}
class Orchestrator {
    public boolean executeOps(OpsOrder order) {
        switch (order) {
            case OPS1:
                return new Ops1().ops();
            case OPS2:
                return new Ops2().ops();
            //...
            default:
                throw new IllegalArgumentException("Not supported.");
        }
        throw new UnsupportedOperationException("This exception should never be reached.");
    }
    public boolean orchestrate(OpsOrder ... orders) {
        for (OpsOrder order : orders) {
            if (!executeOps(orders)) {
                return false;
            }
        }
        return true;
    }
}

通过拥有CommonOps类实现的工厂,这可以更加通用,因此Orchestrator应该不知道将调用哪个CommonOps

final class CommonOpsFactory {
    private CommonOpsFactory () { }
    public static CommonOps create(OpsOrder order) {
        switch (order) {
            case OPS1:
                return new Ops1();
            case OPS2:
                return new Ops2();
            //...
            default:
                throw new IllegalArgumentException("Not supported.");
        }
    }
}
class Orchestrator {
    public boolean executeOps(OpsOrder order) {
        return CommonOpsFactory.create(order).ops();
    }
    public boolean orchestrate(OpsOrder ... orders) {
        for (OpsOrder order : orders) {
            if (!executeOps(orders)) {
                return false;
            }
        }
        return true;
    }
}

我会将命令模式与装饰器结合使用来解决此问题。您的命令,当许多命令时,将相互包装/装饰:

public class Command{
    private Command subCommand;
    public Command(Command subCommand){
        this.subCommand=subCommand;
    }
    public Command(){};
    public Command addSubCommand(Command command)
    {
         subCommand=command;
         return command;
    }
    //A Command class is decorating itself
    //by adding a behavior over its subcommand 
    public void execute() throws CommandExecutionException {
         executeImpl();
         if(subCommand!=null) subCommand.execute();
    }
    protected void executeImpl() throws CommandExecutionException {
         //To be overiden
    }
}
public class CommandA extends Command{
    private CommandAExecutor ops1Handler;
    protected void executeImpl(){
         ops1Handler.ops1();
    }
}
//....
public class CommandN extends Command{
    private CommandNExecutor opsNHandler;
    protected void executeImpl(){
         opsNHandler.opsN();
    }
}
public class Tester{
    public static void main(String[] args){
        Command commandA = new CommandA(new CommandAExecutor());
        Command commandB = new CommandB(new CommandBExecutor());
        Command commandN = new CommandN(new CommandNExecutor());
        //The order here is A, N, B
        commandA.addSubCommand(commandN).addSubCommand(B);
        try{
             commandA.execute();
        }catch(CommandExecutionException e){
              //...failure
        }
    }
}

相关内容

最新更新