Aravind Yarram
Aravind Yarram

Reputation: 80192

Pattern of solution for executing and operation that depends upon multiple conditions

Let us say there are 3 operations ops1(), ops2() and ops3(). The client can request to execute any combination of those 3. For e.g.

This can go on for n ops() though for me its just 5.

What is the simple and elegant way of implementing this? Is there a pattern for this?

Upvotes: 3

Views: 144

Answers (4)

yechabbi
yechabbi

Reputation: 1881

I would use the command pattern in combination with the Decorator for this problem. Your commands, when many, will be wrapping/decorating each others :

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
        }
    }
}

Upvotes: 0

flup
flup

Reputation: 27103

How about you put your ops in a list, look the operations to perform up in that list, and let the operations throw an exception if they fail? Then the perform method can simply try and perform all methods in the desired order until it's done or an exception occurs.

So

private List<Callable> ops;

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

Upvotes: 1

Luiggi Mendoza
Luiggi Mendoza

Reputation: 85799

An approach for this would be

  1. Define a common interface for opsX methods and the classes that implement this method.
  2. Define an enum to know which class implementation of this common interface should be called.
  3. Define a class that will work as an orchestrator for these calls.

An implementation of this design may be

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;
    }
}

This can be even more generic by having a factory of CommonOps class implementations so Orchestrator should not know which CommonOps will be called:

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;
    }
}

Upvotes: 0

MightyPork
MightyPork

Reputation: 18901

I see a solution somewhat like this:

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
        }

    }

}

It's just the general idea, not tested if the syntax is entirely correct.

the "taskFailed" thing is a pseudocode.

Upvotes: 0

Related Questions