I guess most developpers deal everyday with these kind of questions regarding architectural/oop patterns, and I want to get some insights what kind of implementation is the correct one. Time to times I get this kind of implementation:
public interface ISupport
{
void DoAction();
}
public interface ISupportSomeAction
{
void DoSomeAction();
}
public class FooA : ISupport, ISupportSomeAction
{
public void DoAction()
{
}
public void DoSomeAction()
{
}
}
public class FooB : ISupport
{
public void DoAction()
{
}
}
public class DoAction
{
public void Do(List<ISupport> listSupport)
{
foreach (var foo in listSupport)
{
foo.DoAction();
var fooSomeAction = foo as ISupportSomeAction;
if (fooSomeAction != null)
{
fooSomeAction.DoSomeAction();
}
}
}
}
For me the problem with this approach is the cast to ISupportSomeAction to check if the object implement that behaviour. If I had a new behaviour/new interface I have to change this method and add a check to the new behaviour.
So one option that I came up and is obvious is create a new interface, IBundleSupport that aggregate all the behaviours:
public interface ISupport
{
void DoAction();
}
public interface ISupportSomeAction
{
void DoSomeAction();
}
public interface IBundleSupport
{
void DoBundleAction();
}
public class FooA : ISupport, ISupportSomeAction, IBundleSupport
{
public DoBundleAction()
{
DoAction();
DoSomeAction();
}
public void DoAction()
{
}
public void DoSomeAction()
{
}
}
public class FooB : ISupport, IBundleSupport
{
public void DoAction()
{
}
public DoBundleAction()
{
DoAction();
}
}
public class DoAction
{
public void Do(List<IBundleSupport> listSupport)
{
foreach (var foo in listSupport)
{
foo.DoBundleAction();
}
}
}
For me the main advantage of this approach is that the DoAction class wont suffer any modification in the future if a new behaviour like ISupportSomeAction2 is implemented. The responsability of dealing which behaviours to add to the workflow is from the class that implement the IBundleSupport interface.
The main disadvantage is that everytime someone add a new class that implement IBundleSupport must know the set of behaviours, and its order, to add when invoking the DoBundleAction method. In the first example I stated that the behaviour to be invoked is ISupport.DoAction and then, if the object implement the ISupportSomeAction invoke the DoSomeAction method. If you notice the FooA has the responsability to implement the workflow, invoking DoAction follow by DoSomeAction method
Can we follow other approaches? Or having the check if a class implement a certain behaviour is not a code smell at all?
Aucun commentaire:
Enregistrer un commentaire