vendredi 30 mars 2018

Design pattern for replacing nested if statements (arrow anti-pattern)

I noticed my code looks really ugly, and is hard to maintain. Basicaly i need do to some person check. Pseudo code is like this (BTW i can't "cut" anything in query, and it's not realy the point of my question):

List<Person> persons = getPersonsBySomeQuery();

if (checkAnyPersonExists(persons)) {
  if (atLeastOneWithGivenNameExist(persons)) {
    if (noOneWithOtherNameExists(persons)) {
      filteredPersons = filterPersonsWithGivenName(persons);
      if (singleName(filteredPersons)) {
        // single person found
        if (someParameterFromQueryIsTrue) {
          if (someComplicatedLogicIsOK) {
            // found exactly one person, all OK!!!
          } else {
            // found exatcly one person with given name, but not OK
          }
        } else {
           // found exactly one person but parameter from query is not OK
        }
      } else {
        // found only persons with given name, but more then one
      }
    } else {
      // found person(s) with given name, but also some with different name
    }
  } else {
    // found person(s), all have different name
  }
} else {
  // noone found
}

So i don't have that much experience with design patterns, but i read about them, and i started thinking i could implement Chain of Responsibility pattern. Like, every if-else could be one element in chain, and also this filter element on line 6 could also be "Chainable".

In the end it could look something like:

AbstractChainElement getCheckChain() {
   return new CheckAnyExist(
          new CheckOneWIthGivenNameExist(
          new CheckNoOneWithOtherNameExist(
          new FilterOnlyGivenName(
          new CheckIsSingleName(
          new CheckOtherParameters(
          new CheckWithSomeComplicatedLogic()))))));          
}

getCheckChain().doChain(persons);

Do you think it's good way to do it or is there anything more elegant?

With this i could construct chain for checking for different check types also, using factory or even abstract factory pattern.

Something like:

FactoryCheckThesePersonsByTheseParameters implements AbstractFactory {

     List<Person> getPersons() {
       // get persons with THIS query
     }

     AbstractChainElement getCheckChain() {
       // check persons THIS way
     }
}

FactoryCheckThatPersonsByThatParameters implements AbstractFactory {

     List<Person> getPersonsBySomeParameters() {
       // get persons with THAT query
     }

     AbstractChainElement getCheckChain() {
       // check persons THAT way
     }
}

Aucun commentaire:

Enregistrer un commentaire