Design Pattern to implement Business Rules with hundreds of if else in java
Asked Answered
T

6

44

I have to implement certain business rules with hundreds of lines of below code:

if this
      then this
else if
      then this
.
. // hundreds of lines of rules
 else
      that

Do we have any design pattern which can effectively implement this or reuse the code so that it can be applied to all different rules? I heard of Specification Pattern which creates something like the below:

public interface Specification {

boolean isSatisfiedBy(Object o);

Specification and(Specification specification);

Specification or(Specification specification);

Specification not(Specification specification);
}


public abstract class AbstractSpecification implements Specification {

public abstract boolean isSatisfiedBy(Object o);

public Specification and(final Specification specification) {
 return new AndSpecification(this, specification);
}

public Specification or(final Specification specification) {
 return new OrSpecification(this, specification);
}

 public Specification not(final Specification specification) {
 return new NotSpecification(specification);
}
}

And then the implementation of Is, And, Or methods but I think this cannot save me from writing the if-else (maybe my understanding is incorrect)...

Is there any best approach to implement such business rules having so many if-else statements?

EDIT: Just a sample example. A, B, C, etc are properties of a class. Apart from these, there are a similar lot of other rules. I want to make a generic code for this.

    If <A> = 'something' and <B> = ‘something’ then
    If <C> = ‘02’ and <D> <> ‘02’ and < E> <> ‘02’  then
        'something'
    Else if <H> <> ‘02’ and <I> = ‘02’ and <J> <> ‘02’  then
        'something'
    Else if <H> <> ‘02’ and <I> <> ‘02’ and <J> = ‘02’  then
        'something'
    Else if <H> <> ‘02’ and <I> = ‘02’ and <J> = ‘02’  then 
        'something'
    Else if <H> = ‘02’ and <I> = ‘02’ and <J> <> ‘02’  then 
        'something'
    Else if <H> = ‘02’ and <I> <> ‘02’ and <J> = ‘02’  then 
        'something'
    Else if <H> = ‘02’ and <I> = ‘02’ and <J> = ‘02’  then:
        If <Q> = Y then
            'something'
        Else then 
            'something'
Else :
Value of <Z>
Tactful answered 31/5, 2013 at 4:15 Comment(3)
can you provide some sample of your if else statements? if there any similaritiesGinetteginevra
Use of state pattern?Javierjavler
I think the "Chain of Responsibility"-Pattern could be used here: oodesign.com/chain-of-responsibility-pattern.htmlAshlar
A
32

You should check out the Rules Design Pattern http://www.michael-whelan.net/rules-design-pattern/. It looks very similar to the example code you gave and consists of a base interface that defines a method for determining if a rule is satisfied and then various concrete implementations per different rules. As I understand it, your switch statement would turn into some sort of simple loop that just evaluates things until your composition of rules is either satisfied or fails.

interface IRule {
    bool isSatisfied(SomeThing thing);
}

class RuleA: IRule {
    public bool isSatisfied(SomeThing thing) {
        ...
    }
}

class RuleB: IRule {
    ...
}

class RuleC: IRule {
    ...
}

Composition Rules:

class OrRule: IRule {
    private readonly IRule[] rules;

    public OrRule(params IRule[] rules) {
        this.rules = rules;
    }

    public isSatisfied(thing: Thing) {
        return this.rules.Any(r => r.isSatisfied(thing));
    }
}

class AndRule: IRule {
    private readonly IRule[] rules;

    public AndRule(params IRule[] rules) {
        this.rules = rules;
    }

    public isSatisfied(thing: Thing) {
        return this.rules.All(r => r.isSatisfied(thing));
    }
}

// Helpers for AndRule / OrRule

static IRule and(params IRule[] rules) {
    return new AndRule(rules);
}

static IRule or(params IRule[] rules) {
    return new OrRule(rules);
}

Some service method that runs a rule on a thing:

class SomeService {
        public evaluate(IRule rule, Thing thing) {
            return rule.isSatisfied(thing);
        }
    }

Usage:

// Compose a tree of rules
var rule = 
    and (
        new Rule1(),
        or (
            new Rule2(),
            new Rule3()
        )
    );

var thing = new Thing();

new SomeService().evaluate(rule, thing);

This was also answered here: https://softwareengineering.stackexchange.com/questions/323018/business-rules-design-pattern

Asphyxiate answered 20/11, 2017 at 17:24 Comment(1)
You can also check a blog post where they explain how the rules design pattern works michael-whelan.net/rules-design-patternRettke
S
12

Strategy pattern could be useful here. Please check Replace Conditional Logic with Strategy

Senskell answered 31/5, 2013 at 4:30 Comment(1)
it may be not fit into my requirement.I have edited my question to include a sample of conditional logic.I have conditional logic on some properties of a class for rule one and some other properties(may include some properties used in rule one) for rule twoTactful
D
7

You can use Command pattern or Factory pattern.

Command pattern can be used to replace cumbersome switch/if blocks which tend to grow indefinitely as you add new options.

public interface Command {
     void exec();
}

public class CommandA() implements Command {

     void exec() {
          // ... 
     }
}
// etc etc

then build a Map<String,Command> object and populate it with Command instances:

commandMap.put("A", new CommandA());
commandMap.put("B", new CommandB());

then you can replace your if/else if chain with:

commandMap.get(value).exec();

In Factory Pattern you include your if/switch in a Factory which takes care of the ugliness and hides the abundance of ifs. Example code for Factory Pattern.

Deluxe answered 31/5, 2013 at 4:27 Comment(3)
Thanks for the info.Can you provide some sample examples where these patterns can help in reducing if/else .Tactful
Looks like a good example but may be not fit into my requirement.I have edited my question to include a sample of contional logic.I have conditional logic on some properties of a class for rule one and some other properties(may include some properties used in rule one) for rule two.Tactful
Give the credits for the original answer :): #1200146Corron
T
4

Something that might help is a rules engine like Drools. It's not a design pattern though, so this may not be the answer you're looking for. But IMO, you should consider it. Here's a great article on when you should use a rules engine.

Treasatreason answered 31/5, 2013 at 4:20 Comment(2)
Thanks but my requirement is not to use any rule engine,project reasons :( , so I am looking for some design patternsTactful
Agreed with tieTYT. A rules engine is a perfect candidate for implementing BRs. In my personal experience, it produces code that are super clean and easy to maintain. And reduces the development time by orders of magnitude.Nebulous
B
1

A design pattern could help you to make the code more readable or improve its maintainability, but if you really need to evaluate such numbers of conditions, the IF statements cannot be avoided.

I would consider seeing the problem from other point of view (e.g.: do I really need one hundred conditional statements to solve the problem?) and I would try to change or to improve the algorithm.

An Expression Language could provide some help because you could create programmatically a string that represents each IF statement and to evaluate the result using this tool, but you still have to solve the problem related to the execution of the particular logic associated with each condition.

Bailes answered 1/6, 2013 at 18:7 Comment(0)
W
1

A simple strategy demo with python:

class Context(object):
  def __init__(self, strategy):
    self.strategy = strategy

  def execute(self, num1, num2):
    return self.strategy(num1, num2)

class OperationAdd(object):
  def __call__(self, num1, num2):
    return num1 + num2


class OperationSub(object):
  def __call__(self, num1, num2):
    return num1 - num2


if __name__ == '__main__':
  con = Context(OperationAdd())
  print "10 + 5 =", con.execute(10, 5)

  con = Context(OperationSub())
  print "10 - 5 =", con.execute(10, 5)
Winsome answered 2/2, 2015 at 9:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.