Reputation: 14463
I have a use case where the input is set of parameters (say A, B, C, D) and data (say XYZ). Based on the parameters(A,B,C,D) i have to process the data(XYZ) and respond back. The processing logic can be unique or common based on parameters(say do something#1 only when A, do something#2 when A and C, do something#2 when B, C and D and so on). I might also need to maintain the order of processing.
The current implementation is based on if-else loops. I am looking at chain of responsibility, pipeline design patterns. But is there any other suitable design pattern for the above task ?
Example using if-else blocks:
I/P : A={A1,A2,A3},B={B1,B2,B3},C={C1,C2,C3},D={D1,D2,D3} and XYZ="foo"
if (A == A1)
{
//dosomething-A1
if (B == B1)
{
//dosomething-B1
if (C == C2)
{
//dosomething-C2
}
}
else if (B == B2)
{
//dosomething-B2
}
if (C == C2)
{
//dosomething-C2
if (D == D1)
{
//dosomething-D1
}
else if (D == D3)
{
//dosomething-D3
}
}
}
else if (A == A2)
{
//dosomething-A2
...
}
else if (A == A3)
{
//dosomething-A3
...
}
Upvotes: 5
Views: 278
Reputation: 1263
Your list of if-then-else statements reminds me of a rule-based system. A rule base is in essence a database containing rules of the form Condition -> Action
. The implementation of a condition in Java 8 could look like this:
@FunctionalInterface
interface Condition {
boolean matches(A a, B b, C c, D d);
}
For the Action
you could simply use a Runnable
. Based on your code the rulebase definition could be defined as follows:
static final Map<Condition, Runnable> BASE =
ImmutableMap.<Condition, Runnable>builder()
.put((a, b, c, d) -> a == A1, () -> doSomethingA1())
.put((a, b, c, d) -> a == A1 && b == B1, () -> doSomethingB1())
.put((a, b, c, d) -> a == A1 && b == B1 && c == C2, () -> doSomethingC2())
.put((a, b, c, d) -> a == A1 && b == B2, () -> doSomethingB2())
.put((a, b, c, d) -> c == C2, () -> doSomethingC2())
.put((a, b, c, d) -> c == C2 && d == D1, () -> doSomethingD1())
.put((a, b, c, d) -> c == C2 && d == D3, () -> doSomethingD3())
.put((a, b, c, d) -> a == A2, () -> doSomethingA2())
.put((a, b, c, d) -> a == A3, () -> doSomethingA3())
.build();
To use this rule base you can simply define the following method:
static void evaluate(A a, B b, C c, D d) {
BASE.entrySet().stream()
.filter((entry) -> entry.getKey().matches(a, b, c, d))
.forEach((e) -> e.getValue().run());
}
Which allows you to call it like this:
evaluate(A1, B1, null, null);
// executes doSomethingA1() and doSomethingB1()
Upvotes: 0
Reputation: 11453
Without real word case it is hard to say, but most likely you will be able to decrease size of your if/else tree with good hierarchy of classes.
Polymorphism will make it more object oriented as well.
Upvotes: 0
Reputation: 956
Look for something like command pattern. Based on the parameters data need to be processed. Internal implementation should not be exposed outside. So, from exposed interface perspective it has to take parameter and data and command pattern need to identify which method to execute based on parameters.
Upvotes: 3
Reputation: 2739
Chain seem to fit this very well, if it is reused. Another option is to use handlers stored in a map, where the key is the appropriate parameter value. This works well for limited set of possible values passed as the parameters. You'll get something like:
handlers.get( a ).handle(XYZ)
So, completely if-less on your part. But again, this does not fit all purposes.
Upvotes: 4