I have following C# code. It works fine; but the GetDestination()
method is cluttered with multiple if
conditions by using is operator.
In .Net 4.0 (or greater) what is the best way to avoid these “if” conditions?
EDIT: Role is part of the business model, and the destination is purely an artifact of one particular application using that business model.
CODE
public class Role { }
public class Manager : Role { }
public class Accountant : Role { }
public class Attender : Role { }
public class Cleaner : Role { }
public class Security : Role { }
class Program
{
static string GetDestination(Role x)
{
string destination = @"\Home";
if (x is Manager)
{
destination = @"\ManagerHomeA";
}
if (x is Accountant)
{
destination = @"\AccountantHomeC";
}
if (x is Cleaner)
{
destination = @"\Cleaner";
}
return destination;
}
static void Main(string[] args)
{
string destination = GetDestination(new Accountant());
Console.WriteLine(destination);
Console.ReadLine();
}
}
REFERENCES
Approach 1 (Selected): Using
dynamic
keyword to implementmultimethods
/double dispatch
Approach 2: Use a
dictionary
to avoidif
blocks as mentioned in Jon Skeet’s answer below.Approach 3: Use a
HashList
withdelegates
if there is condition other than equality (For example, if input < 25). Refer how to refactor a set of <= , >= if...else statements into a dictionary or something like thatApporach 4: Virtual Functions as mentioned in MarcinJuraszek’s answer below.
MultiMethods / Double Dispatch approach using dynamic keyword
Rationale: Here the algorithm changes based on the type. That is, if the input is Accountant, the function to be executed is different than for Manager.
One way to do it would be to use a map instead of an if:
Further reading: http://www.hanselman.com/blog/BackToBasicsMovingBeyondForIfAndSwitch.aspx
Here's one option:
Note:
class Foo : Manager
); you could do that by going up the inheritance hierarchy if necessaryHere's a version which does deal with both of those points, at the cost of complexity:
EDIT: It would be cleaner if
Role
itself had aDestination
property. This could either be virtual, or provided by theRole
base class.However, it could be that the destination is really not something the
Role
should concern itself with - it could be thatRole
is part of the business model, and the destination is purely an artifact of one particular application using that business model. In that sort of situation, you shouldn't put it intoRole
, as that breaks separation of concerns.Basically, we can't tell which solution is going to be most suitable without knowing more context - as is so often the way in matters of design.
Role should have a virtual function that would return destination:
And all the classes should override this function and return the correct string. Then in the code you would have:
I hope that helps. There may be typos, I am writing from head.
This is a strongly typed, imperative language so
if
statements and type checking are going to happen.Having said that, have you considered a
virtual
method onRole
that can be overridden to provide a destinationstring
?A further alternative, a lookup table!
Having
virtual
property which would be overriden in derived classes should do the trick:I didn't make the property abstract, to provide default
Home
value when it's not overriden in derived class.Usage: