Substitute Enum switch with design pattern (IOC)
I've got an event handler which receives an eventargs 开发者_开发百科object inside which is an enumerated value that further refines the information inside. It looks something like
public enum StatusCallbackType { Status1, Status2, Status3, Status4 }
public class StatusEventArgs
{
public StatusCallbackType Type {get;set;}
public StatusData Data {get; set;}
}
Statusdata is a base abstract class that changes depending on the given CalllbackType.
Now the code that handles the event looks similar to
switch e.Type
{
case Status1:
DoAction1(e.Data as Opt1Data);
break;
case Status2:
DoAction1(e.Data as Opt2Data);
break;
case Status3:
DoAction1(e.Data as Opt3Data);
break;
}
The problem is if we change the StatusNotifications or want to change the way they're handled we have to adjust the switch which could get really big, and I was thinking about using something that allowed me to inject a handler for any given status.
On the other hand I don't really need it right now. The switch solutions works, but it's starting to get big so I'm fighting between my feeling that it is not maintanble and YAGNI.
Is there any pattern that allows to convert that kind of switches to and IOC pattern? Do you think I should actually bother refactoring that switch?
I think you can refactor to a chain-of-responsibility pattern. Each switch statement becomes an handler object in a collection that either handles the notification or the notification gets passed along to the next.
As far as injection, you will be able to vary the number of handlers without modifying the client code and inject mocks/stubs for testing.
To answer whether or not you should refactor, there is nothing wrong with a switch statement in itself, so long as it only appears once and remains simple. You will want to refactor if you start to notice duplication or other code smells that can be fixed with a pattern.
I would consider to use something like Abstract Factory pattern. It is very useful in relation to IoC because it can encapsulate complex logic that creates other Dependencies. Then you could inject your abstract factory with a IoC tool and get a rid of the switch statement.
I would use something like this perhaps:
public interface IStatusHandler
{
bool Handle(StatusData statusData);
}
public class Status1Handler : IStatusHandler
{
public bool Handle(StatusData statusData)
{
if (statusData as Opt1Data == null) return false; // you don't need Type anymore
...
return true;
}
}
public class StatusManager
{
private IList<IStatusHandler> handlers;
public StatusManager(IList<IStatusHandler> handlers) // inject with IoC here
{
this.handlers = handlers;
}
public void ProcessStatus(StatusEventArgs args)
{
foreach(var handler in handlers)
if (handler.Handle(args.Data)) return;
throw new Exception("No handler for this kind of status!");
}
}
精彩评论