Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When "if else"/"instance of" are inevitable, how do we improve the design apart from using visitor pattern?

When we have an object hierarchy that is purely a inheritance of semantic and not of behaviors,then inevitably we need to write "instanceof" or "if/else" everywhere to do run time type checking.

E.g.

If I have a object hierarchy which has

Class Function

Class Average extends Function

Class Sum extends Function

Class Max extends Function

If there is a method called calculate() in these classes, then we do not have problem, we can just take the advantage of polymorphism and this design satisfies the LSP.

However what if we do not want to add this calculate() method to this hierarchy for some reason, these objects are purely plain object stateless objects just represent the semantic.

Then we are forced to write the following code everywhere :

if (function instanceof Average)
//perform average
else if(function instanceof Sum)
//perform sum
else if(function instanceof Max)
//perform max

The code above indicates a bad design, because you write this code everywhere and this design is fragile and is hard to change later on. I guess if the number functions are limited and the calculation of function are in a single place this perhaps is ok depends on the complexity.

What I've known so far is that to solve above approach, the only possible way is to implement a visitor pattern, is there any other way to solve the above design apart from using visitor pattern?

One problem I can see from visitor pattern is that visitor pattern's accept method does not return value, this is not convenient sometime if the accept() method doesn't fully satisfy the requirement.

like image 658
grumpynerd Avatar asked May 21 '13 08:05

grumpynerd


1 Answers

If you still know the types at compile time you can use a helper class:

class Function {
}

class Average extends Function {
}

class Sum extends Function {
}

class Max extends Function {
}

class FunctionHelper {
  public Number calculate(Average a) {
    return null;
  }

  public Number calculate(Sum s) {
    return null;
  }

  public Number calculate(Max a) {
    return null;
  }

  public Number calculate(Function a) {
    return null;
  }

}

Generally you'd make the helper methods static but you are not restricted to that - there are some rather interesting things you can do with multiple flavours of helper class.

like image 115
OldCurmudgeon Avatar answered Oct 11 '22 22:10

OldCurmudgeon