How to safe implement the use of valueOf in case i get a String different than the supported on the enum ACTION. I mean is possible to force to ACTION.valueOf(valueToCompare) to get a valid value even when happens that valueToCompare is not a valid enum member
I get an expected execution when valueToCompare is "CRY" or "CRYALOT" or "cryalot" etc.
And i get java.lang.IllegalArgumentException on cases like in the code.
public enum ACTION{
CRY,
CRYALOT;
}
public static void main(String[] args) {
String valueTocompare = "posible not expected value".toUpperCase();
switch (ACTION.valueOf(valueToCompare)) {
case CRY:
System.out.println("Cry");
break;
case CRYALOT:
System.out.println("Cry a lot");
break;
default:
System.out.println("catch posible not expected value");
break;
}
}
EDIT & used SOLUTION:
I solved this by using a try-catch as #Peter Lawrey suggested:
public enum ACTION{
CRY,
CRYALOT,
NOTVALID;
}
public static void main(String[] args) {
String valueToCompare = "NOTVALID";
ACTION action;
try {
valueToCompare= "variable posible not expected value".toUpperCase();
action = ACTION.valueOf(valueToCompare);
} catch(IllegalArgumentException e){
System.out.println("Handled glitch on the Matrix");
action = ACTION.NOTVALID;
}
switch (action) {
case CRY:
System.out.println("Cry");
break;
case CRYALOT:
System.out.println("Cry a lot");
break;
default:
System.out.println("catch posible not expected value");
break;
}
System.out.println("We continue normal execution on main thread...");
}
You need to catch the IllegalArgumentException
try {
switch (ACTION.valueOf(valueToCompare)) {
}
} catch (IllegalArgumentException iae) {
// unknown
}
Or you can create your own function which does this.
public static <E extends Enum<E>> E valueOf(E defaultValue, String s) {
try {
return Enum.valueOf(defaultValue.getDeclaringClass(), s);
} catch (Exception e) {
return defaultValue;
}
}
Note: switch(null) throws a NullPointerException rather than branching to default:
Using exceptions for flow control is considered as a bad practice.
String valueToCompare = value.toUpperCase();
ACTION action = Arrays.stream(ACTION.values())
.filter(a -> a.name().equals(valueToCompare)).findFirst().orElse(ACTION.NOTVALID);
the problem here is this line:
ACTION.valueOf(valueToCompare) - you are trying to run valueOf on valueToCompare, and its erroring out since the value isn't an enum in ACTION. It's not even making the switch statement to print out the default msg.
Have a look at the changes I've done, you'll notice a few things, the main one being actionToCompare...
enum Action {
CRY,
CRYALOT,
EXAMPLE
}
public static void main(String[] args) {
Action actionToCompare = Action.EXAMPLE;
switch (actionToCompare) {
case CRY:
System.out.println("Cry");
break;
case CRYALOT:
System.out.println("Cry a lot");
break;
default:
System.out.println("catch posible not expected value");
break;
}
}
if you insist on using a String over converting it to the enum Action, wrap it in a try...catch statement so if an invalid string is passed in it can handle the error.
You can always build yourself a reverse-lookup.
enum Action {
CRY,
CRYALOT,
EXAMPLE;
// Lookup map for actions in string form.
static Map<String,Action> lookup = Arrays.stream(values()).collect(Collectors.toMap(
// Key is name in lowercase.
a -> a.name().toLowerCase(),
// Value is the Action.
a -> a));
public static Action lookup(String name) {
return lookup.get(name.toLowerCase());
}
}
public void test() throws Exception {
System.out.println(Action.lookup("cry"));
System.out.println(Action.lookup("CryAlot"));
}
A solution that does not involve exceptions in the control flow and enables mapping the enum name or the action name to the action with a default behavior in case there is no mapping entry:
public enum CryActions {
CRY_A_LITTLE("Cry a little", CryALittleActionHandler::new), CRY_A_LOT("Cry a lot", CryALotActionHandler::new), DEFAULT("Default", DefaultCryActionHandler::new);
private String actionName;
private Supplier<CryActionHandler> supplier;
private CryActions(String actionName, Supplier<CryActionHandler> supplier) {
this.actionName = actionName;
this.supplier = supplier;
PossibleCryActions.byEnumName.put(name(), this);
PossibleCryActions.byActionName.put(actionName, this);
}
public void handleAction() {
supplier.get().handleAction();
}
public String getActionName() {
return actionName;
}
public static CryActions fromEnumName(String enumName) {
return PossibleCryActions.byEnumName.computeIfAbsent(enumName, x -> DEFAULT);
}
public static CryActions fromActionName(String actionName) {
return PossibleCryActions.byActionName.computeIfAbsent(actionName, x -> DEFAULT);
}
private static class PossibleCryActions {
private static Map<String, CryActions> byEnumName = new HashMap<>();
private static Map<String, CryActions> byActionName = new HashMap<>();
}
}
public interface CryActionHandler {
void handleAction();
}
public class CryALittleActionHandler implements CryActionHandler {
#Override
public void handleAction() {
System.out.println("Just crying a little...");
}
}
public class CryALotActionHandler implements CryActionHandler {
#Override
public void handleAction() {
System.out.println("Crying a river...");
}
}
public class DefaultCryActionHandler implements CryActionHandler {
#Override
public void handleAction() {
System.out.println("Just crying as default behavior...");
}
}
public class Main {
public static void main(String[] args) {
CryActions.fromEnumName("CRY_A_LITTLE").handleAction();
CryActions.fromEnumName("CRY_A_LOT").handleAction();
CryActions.fromEnumName("CRY_UNEXPECTEDLY").handleAction();
CryActions.fromActionName("Cry a little").handleAction();
CryActions.fromActionName("Cry a lot").handleAction();
CryActions.fromActionName("Cry unexpectedly").handleAction();
}
}
Kotlin version:
inline fun <reified T : Enum<T>> safeValueOf(name: String, defaultValue: T): T =
try {
java.lang.Enum.valueOf(T::class.java, name) ?: defaultValue
} catch(e: IllegalArgumentException) {
defaultValue
}
Related
My program parses WebAssembly instructions and makes decisions based on the context of the current instruction. So, the MWE for my algorithm looks like this:
public class Main {
public interface Context {
String name();
}
static class M implements Context {
public String name() {
return "Context M: ";
}
}
static class N implements Context {
public String name() {
return "Context N: ";
}
}
public interface Instruction {
int getId();
String run();
}
static class A implements Instruction {
public int getId() {
return 0;
}
public String run() {
return "The work of A";
}
}
static class B implements Instruction {
public int getId() {
return 1;
}
public String run() {
return "The work of B";
}
}
static void work(Context context, Instruction instruction) {
switch (instruction.getId()) {
case 0:
workOnId0(context, (A) instruction);
break;
case 1:
workOnId1(context, (B) instruction);
break;
default:
throw new RuntimeException("Failed to recognize instruction");
}
}
static void workOnId0(Context context, A instruction) {
System.out.println(context.name() + instruction.run());
}
static void workOnId1(Context context, B instruction) {
System.out.println(context.name() + instruction.run());
}
static void workOnId1(N context, B instruction) {
System.out.println("This is corner case logic for this context!");
}
public static void main(String[] args) {
N context = new N();
B instruction = new B();
work(context, instruction);
}
}
As you can see from above, when my instruction is B, then the ordinary work should happen in workOnId1, but in case my context is specifically N, I would like some special work done, which is represented by a different overload of workOnId1.
Unfortunately, the special overload never gets called. How can I make the overload resolution work?
workOnId1(Context context, B instruction) will always be called, because you have a Context object.
You are going to need to differentiate method calls by casting to N. If this doesn't work well within your model, since I'm guessing this is only a small example, you may need to rethink your overall design. A simple solution would be:
if(context instanceof N) {
workOnId1((N)context, (B)instruction);
} else {
workOnId1(context, (B) instruction);
}
you can change one line under case:1 as below to achieve your target
switch (instruction.getId()) {
case 0:
workOnId0(context, (A) instruction);
break;
case 1:
workOnId1((context instanceof N)? (N)context :context, (B) instruction); break;
default:
throw new RuntimeException("Failed to recognize instruction");
}
The use case is there is a set of methods which need to be executed based on whether the previous one has returned true or not.
For example:
class Test {
boolean method1() {...}
boolean method2() {...}
boolean method3() {...}
...
void callAll() {
if(method1()) {
if(method2() {
if(method3() {
...
}
}
} else {
error();
}
}
}
There has to be an else for all the ifs.
Is there a better way of handling this scenario?
I would just do it like this:
void callAll(){
if(method1() && method2() && method3()){
// all passed
} else {
error();
}
}
Java short-circuits the && logical operation so failure in a previous method here will prevent running the next one.
If in error() you need to know which of the methods failed, you could declare an error message field for storing the information within the class and set its value corresponding the failure:
private String errorMessage;
//...
boolean method2() {
// something went wrong
errorMessage = "Failed to do method2 stuff";
}
Are more elegant way to achieve the same would be to use the Chain of responsibility design pattern and encapsulate the boolean methods in their own handler objects. Doing this would however require more refactoring to the code you currently have and more information about your specific use case.
It's easy enough to write your own varargs method to do this:
public static void run(Supplier<Boolean>... methods) {
for (Supplier<Boolean> method : methods) {
if (!method.get()) return;
}
}
Sample usage:
run(this::method1, this::method2, this::method3);
You can use some form of Observable pattern for these kind of thins too. In most normal cases it seems a bit silly to implement it but otherwise a great way to decouple code from control structures if you have a lot of these. Note that ObservableBoolean is an Android class, but just showing the logic here:
ObservableBoolean a = new ObservableBoolean();
ObservableBoolean b = new ObservableBoolean();
public void call() {
a.addOnPropertyChangedCallback(new OnPropertyChangedCallback() {
#Override
public void onPropertyChanged(android.databinding.Observable sender, int propertyId) {
method2();
}
});
b.addOnPropertyChangedCallback(new OnPropertyChangedCallback() {
#Override
public void onPropertyChanged(android.databinding.Observable sender, int propertyId) {
//..you end the "chain" here
}
});
method1();
}
void method1() {
if(true) {
a.set(true);
}
else {
b.set(false);
}
}
void method2() {
if(true) {
b.set(true);
}
else {
b.set(false);
}
}
I use this technique - although some would find it odd.
boolean method1() {
System.out.println("method1");
return true;
}
boolean method2() {
System.out.println("method2");
return false;
}
boolean method3() {
System.out.println("method3");
return true;
}
void callAll() {
boolean success = method1();
success = success ? method2() : success;
success = success ? method3() : success;
if (success) {
System.out.println("Success");
} else {
System.out.println("Failed");
}
}
I could suggest you to use RX approach, with rxjava it should look like
public boolean test1() {
Log.d("TESTIT", "test1 called");
return true;
}
public boolean test2() {
Log.d("TESTIT", "test2 called");
return true;
}
public boolean test3() {
Log.d("TESTIT", "test3 called");
return false;
}
public boolean test4() {
Log.d("TESTIT", "test4 called");
return true;
}
public boolean elseMethod(boolean result) {
if (result) return true;
else {
Log.d("TESTIT", "ELSE");
}
return false;
}
public void chainedCallback() {
Observable.just(test1())
.filter(this::elseMethod)
.flatMap(aBoolean -> Observable.just(test2()))
.filter(this::elseMethod)
.flatMap(aBoolean -> Observable.just(test3()))
.filter(this::elseMethod)
.flatMap(aBoolean -> Observable.just(test4()))
.filter(this::elseMethod)
.subscribe();
}
call for chainedCallback() will print
test1 called
test2 called
test3 called
ELSE
You define a class that holds an action (calling one of the methods) and with a corresponding failure handler (the else block of an if call)
public static class ActionWithFailureHandler {
private Supplier<Boolean> action;
private Runnable failureHandler;
public ActionWithFailureHandler(Supplier<Boolean> action, Runnable failureHandler) {
this.action = action;
this.failureHandler = failureHandler;
}
//Getters for the instance variables
}
You make a list of the above and call each of the actions till one of the following happens
One of the actions fails (i.,e one of the method returns false). In that case, you need to execute the failureHandler corresponding to that action.
All actions pass. In this case, execute the successHandler (the logic that you execute when all methods return true).
private static void callAll(List<ActionWithFailureHandler> actionWithFailureHandlers, Runnable successHandler) {
actionWithFailureHandlers.stream()
.filter(actionWithFailureHandler -> !actionWithFailureHandler.getAction().get())
.findFirst() //Find first failing action
.map(ActionWithFailureHandler::getFailureHandler)
.orElse(successHandler)
.run(); //You might be running either the successHandler or the failureHandler for the first failed action
}
Driver code:
public static void main(String[] args) {
Test test = new Test();
List<ActionWithFailureHandler> actionWithFailureHandlers = com.google.common.collect.ImmutableList.of(
new ActionWithFailureHandler(test::method1, () -> System.out.println("Method 1 returned false")),
new ActionWithFailureHandler(test::method2, () -> System.out.println("Method 2 returned false")),
new ActionWithFailureHandler(test::method3, () -> System.out.println("Method 3 returned false"))
);
callAll(actionWithFailureHandlers, () -> System.out.println("All returned true"));
}
Exception firstly comes to my mind, but see the link below to learn more about its performance hit.
Original answer. I would do..
public class MyException extends Exception
{
}
public void doAll()
{
try
{
method1();
method2();
method3();
}catch (MyException e)
{
error();
}
}
And let's assume that method1, method2, and method3 throws MyException when it fails.
Though it does not fit your question, it is a good pattern to use Exceptions.
public class Helper
{
public Helper(Method m)
{
this.method=m;
}
public void Do() throws MyException
{
if(method.invoke()==false)
throw new MyException ();
}
}
Using this class,
public void doAll()
{
Helper [] helpers={new Helper(this::method1), new Helper(this::method2), new Helper (this::method3)};
try
{
for(Helper helper:helpers)
{
helper.Do();
}
}catch (MyException e)
{
error();
}
}
But
according to the comment of #dilix and the link, it can be a performance-expensive strategy.
So let's use them only for their purpose.
I'm sending more than 1 request to a web service, below there is an example of that requests. Its important for my application to get the answer from the web service so if there is an exception application will try couple of times to get the answer.
Because of that getting something simple like
deviceList = serviceAdapter.getDevices(); is turn into below code.
boolean flag = true;
int counter = 1;
List<Device> deviceList = null;
while (flag) {
try {
deviceList = serviceAdapter.getDevices();
flag = false;
} catch (Exception e) {
try {
if (counter == 5) {
System.out.println("Timeout Occured!");
flag = false;
} else {
Thread.sleep(1000 * counter);
counter++;
}
} catch (InterruptedException e1) {
}
}
}
And in my application i have lots of requests which means there will be more ugly codes. Is there a way where i will call my request methods as parameter for another method something like this:
deviceList = wrapperMethod(serviceAdapter.getDevices());
Problem is there will be different type of requests, so they will return different type objects (list,array,string,int) and their paramaters will change. Is there a suitable solution in java for this problem?
You can pass a Supplier<T> to the wrapperMethod:
public static <T> T wrapperMethod (Supplier<T> supp) {
boolean flag = true;
int counter = 1;
T value = null;
while (flag) {
try {
value = supp.get();
flag = false;
} catch (Exception e) {
try {
if (counter == 5) {
System.out.println("Timeout Occured!");
flag = false;
} else {
Thread.sleep(1000 * counter);
counter++;
}
} catch (InterruptedException e1) {
}
}
}
}
And call it with:
List<Device> deviceList = wrapperMethod (() -> serviceAdapter.getDevices());
I'm afraid, though, that it will limit the methods you call within the lambda expression to throw only RuntimeExceptions.
You can use some command implementation to execute some specific codes :
Here is a simple example of a command
interface Command{
void run();
}
And a couple of implementations :
class SayHello implements Command{
#Override
public void run() {System.out.println("Hello World");}
}
class KillMe implements Command{
public void run() { throw new RuntimeException();};
}
All we have to do to execute those method is to receive an instance of Command and run the method :
public static void execCommand(Command cmd) {
cmd.run();
}
And to use this
public static void main(String[] args) {
execCommand(new SayHello());
execCommand(new KillMe());
}
Hello World
Exception in thread "main" java.lang.RuntimeException
It also accepts lambda expression :
execCommand(() -> System.out.println("Say goodbye"));
And method reference :
public class Test{
public static void testMe() {
System.out.println("I work");
}
}
execCommand(Test::testMe);
Note that I didn't specify that this could throw Exception so I am limited to unchecked exception like RuntimeException but of course void run() throws Exception could be a solution. That way you can do what ever you want.
Full example (with exceptions) :
public class Test {
public static void main(String[] args) {
try {
execCommand(new SayHello());
execCommand(() -> System.out.println("Say goodbye"));
execCommand(Test::testMe);
execCommand(new KillMe());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void testMe() throws IOException{
System.out.println("I work");
}
public static void execCommand(Command cmd) throws Exception {
cmd.run();
}
}
interface Command{
void run() throws Exception;
}
class SayHello implements Command{
#Override
public void run() {System.out.println("Hello World");}
}
class KillMe implements Command{
public void run() { throw new RuntimeException();};
}
Output:
Hello World
Say goodbye
I work
Exception in thread "main" java.lang.RuntimeException
at main.KillMe.run(Test.java:39)
at main.Test.execCommand(Test.java:25)
at main.Test.main(Test.java:17)
You can use #RetryOnFailure annotation from jcabi-aspects
Create a wrapper method then annotate it to enable auto retry upon Exception
As an example:
#RetryOnFailure(attempts = 5)
List<Device> retryWhenFailed(ServiceAdapter serviceAdapter) throws Exception {
return serviceAdapter.getDevices();
}
This solution uses Generics to be able to handle different Object with most of the same code and a Runnable to execute the fetching.
With this solution, you would need only to write the different adapters extending from ServiceAdapter<T extends Fetchable> to implement the logic to fetch the data for each different class (which would have to implement Fetchable).
Define an interface that abtracts the objects that can be fetched by the different services.
package so50488682;
public interface Fetchable {
}
The ojbect that are to be retrieved implement this interface so you can use the same code for different classes.
package so50488682;
public class Device implements Fetchable{
private String id;
public Device(String id) {
this.id = id;
}
public String toString() {
return "I am device " + id;
}
}
Define an abstract ServiceAdapter that the different service adapters will extend to implement the logic for each kind of object to be retrieved. We add throws Exception to the get() method so this method cand just delegate the exception handling to the FetcherService and decide if it should retry or fail.
package so50488682;
import java.util.List;
public abstract class ServiceAdapter<T extends Fetchable> {
public abstract List<T> get() throws Exception;
}
This is an example of an implementation done to get objects of class Device.
package so50488682;
import java.util.ArrayList;
import java.util.List;
public class DeviceServiceAdapter extends ServiceAdapter<Device>{
#Override
public List<Device> get() throws Exception{
List<Device> rtn = new ArrayList<>();
// fetch the data and put it into rtn, this is a mock
Device d = new Device("1");
rtn.add(d);
d = new Device("2");
rtn.add(d);
d = new Device("3");
rtn.add(d);
//
return rtn;
}
}
Finally this is a generic solution to run the different service adapters.
public class FetcherService<T extends Fetchable> implements Runnable{
List<T> result = new ArrayList<>();
ServiceAdapter<T> serviceAdapter;
#Override
public void run() {
boolean flag = true;
int counter = 1;
while (flag) {
try {
result = serviceAdapter.get();
flag = false;
} catch (Exception e) {
try {
if (counter == 5) {
System.out.println("Timeout Occured!");
flag = false;
} else {
Thread.sleep(1000 * counter);
counter++;
}
} catch (InterruptedException e1) {
throw new RuntimeException("Got Interrupted in sleep", e);
}
}
}
}
public List<T> getResult() {
return result;
}
public void setResult(List<T> result) {
this.result = result;
}
public void setAdapter(ServiceAdapter<T> adapter) {
this.serviceAdapter = adapter;
}
}
From the main or calling program it work like this:
package so50488682;
import java.util.List;
public class SO50488682 {
public static void main(String args[]) {
try {
DeviceServiceAdapter deviceServiceAdapter = new DeviceServiceAdapter();
FetcherService<Device> deviceFetcherService = new FetcherService<>();
deviceFetcherService.setAdapter(deviceServiceAdapter);
deviceFetcherService.run();
List<Device> devices = deviceFetcherService.getResult();
for(Device device : devices) {
System.out.println(device.toString());
}
}catch(Exception e) {
System.out.println("Exception after retrying a couple of times");
e.printStackTrace();
}
}
}
Considering this class
package com.bluegrass.core;
public class Constants {
public static final String AUTHOR="bossman";
public static final String COMPANY="Bluegrass";
//and many more constants below
}
I want to create a function that goes like this:
getConstantValue("AUTHOR") //this would return "bossman"
Any ideas how this can be done?
You can use reflection:
public static String getConstantValue(String name) {
try {
return (String) Constants.class.getDeclaredField(name).get(null);
} catch (Exception e) {
throw new IllegalArgumentException("Constant value not found: " + name, e);
}
}
UPDATE: Enum solution.
If you can change the Constants class to be an enum, it would be like this instead:
private static String getConstantValue(String name) {
return Constants.valueOf(name).getText();
}
But that requires something like this for Constants:
public enum Constants {
AUTHOR("bossman"),
COMPANY("Bluegrass");
private final String text;
private Constants(String text) {
this.text = text;
}
public String getText() {
return this.text;
}
}
Probably the simplest solution (and also work with enums instead of String is typesafe) is to work with enum, provided you are able to change the public static final fields into an enum.
public enum Constants {
AUTHOR("bossman"),
COMPANY("Bluegrass");
private final String content;
Constants (String content) {
this.content= content;
}
public String getContent() {
return content;
}
public static Constants getConstant(String content) {
for (Constants constant : Constants.values()) {
if (constant.getContent().equals(content)) {
return constant;
}
}
return null; //default value
}
}
Usage:
Constants.valueOf("AUTHOR") == Constants.AUTHOR
Constants.getConstant("bossman") == Constants.AUTHOR
Constants.AUTHOR.getContent() == "bossman"
So instead of OP's getConstantValue("AUTHOR") it would be Constants.valueOf("AUTHOR").getContent()
There is a multitude of methods to solve this.
One way is to use a switch.
Example:
public String foo(String key) throws AnException {
switch (key) {
case case1:
return constString1;
case case2:
return constString2;
case case3:
return constString3;
...
default:
throws NotValidKeyException; //or something along these lines
}
}
The other method is to create a map<string,string> and fill it with the desired key,pairs.
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.
perform(1): Should execute ops1()
perform(2): Should execute ops2()
perform(1, 2): Should execute ops1() and if ops1() is successful then execute ops2()
perform(1, 2, 3): Should execute ops1() and if ops1() is successful then execute ops2() and if both ops1() and ops2() are successful then execute ops3()
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?
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) {
}
}
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.
An approach for this would be
Define a common interface for opsX methods and the classes that implement this method.
Define an enum to know which class implementation of this common interface should be called.
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;
}
}
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
}
}
}