beatrice
beatrice

Reputation: 4421

Design pattern for related nested conditionals

I know that most of the conditional hell can be simplified on a more OO way by using design patterns like strategy,command,chain of responsibility.

What about conditions which don't contain many side branches (branches on the same level) but heavily nested and each condition depends on the result of the previous one.

here is an example:

nestedFunction(input: Input){
    if(input!=null){
      a = func1(input)
      if(p(a)){    // where p() is a predicate
         b = func2(a)
         if(p(b)){
           c = func3(b)
           if(p(c)){
              // dosomething1
           } else {
             // dosomething2
          }
         } else {
           // dosomething3
         }
      } else {
         // dosomething4
      }
    } else {
     // dosomething5
    }      
}

I can simplify it a bit by extracting each nested nested conditional into different function as describe here : https://blog.codinghorror.com/flattening-arrow-code/

But I am curious is there any more OO friendly way to do this?

Upvotes: 0

Views: 267

Answers (1)

plalx
plalx

Reputation: 43718

You could probably use the Pipeline Pattern.

A pipeline is a series of IO steps linked together in a way that the next step processes the output of the previous step (think unix-style piping). You could handle conditionals with branching steps which only does delegation rather than actual processing.

e.g. Obviously the example is a bit silly and over-engineered as standard function composition would just be much simpler and elegant. I would certainly start with extracting code in smaller functions and compose the branching with standard techniques and then if that's still combersome you can try moving to an alternate approach.

const pipeline = ifNotNull(
  input => pipe(
    input => input.toUpperCase(),
    input => input + " added suffix",
    console.log
  )(input), 
  () => console.log('input was null')
);


pipeline(null);
pipeline("some value");


function ifNotNull(thenStep, elseStep) {
  return match({
    condition: input => input !== null,
    body: thenStep
  }, {
    condition: () => true,
    body: elseStep
  });
}

function match(...branches) {
  return input => {
    for (branch of branches) {
      if (branch.condition(input)) {
        return branch.body(input);
      }
    }
  };
}

function pipe(...steps) {
  return input => {
    for (step of steps) {
      input = step(input);
    }
    
    return input;
  };
}

Upvotes: 1

Related Questions