假设有 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"是一个伪代码。
一种方法是
- 为
opsX
方法和实现此方法的类定义公共接口。 - 定义一个
enum
以了解应调用此公共接口的哪个类实现。 - 定义一个将用作这些调用的业务流程协调程序的类。
此设计的实现可能是
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
}
}
}