I am always struggling with decoration + interfaces. Say I have the following 'behavior' interfaces :
interface IFlyable { void Fly();}
interface ISwimmable { void Swim();}
A main interface
interface IMainComponent { void DoSomethingA(); void DoSomethingB();}
A decorator on the main interace
public class Decorator : IMainComponent
{
public virtual void DoSomethingA()
{
decorated.DoSomethingA();
}
public virtual void DoSomethingB()
{
decorated.DoSomethingB();
}
}
My issue is how to forward all the interfaces implemented by the decorated object to the decorator. A solution is to make the decorator implementation the interfaces :
public class Decorator : IMainComponent, IFlyable, ISwimmable
{
public virtual void Fly()
{
((IFlyable)decorated).Fly();
}
public virtual void Swim()
{
((ISwimmable)decorated).Swim();
}
But I don't like it because :
- It may looks like the "Decorator" implement an interface while it is not the case (Cast exception at run time)
- This is not scalable, I need to add each new interface (and not forget about this addition)
An other solution is to add "a manual cast" that propagates throw the decoration tree :
public class Decorator : IMainComponent
{
public T GetAs<T>()
where T : class
{
//1. Am I a T ?
if (this is T)
{
return (T)this;
}
//2. Maybe am I a Decorator and thus I can try to resolve to be a T
if (decorated is Decorator)
{
return ((Decorator)decorated).GetAs<T>();
}
//3. Last chance
return this.decorated as T;
}
But the issues are :
- The caller can be manipulating the wrapped object after a call to GetAs().
- This can lead to confusion/unwanted behaviour if using a method from IMainComponent after a call on GetAs (something like ((IMainComponent)GetAs()).DoSomethingB(); ==> this may call the implementation of the wrapped object, not the full decoration.
- The GetAs() method need to be called and exiting code with cast/regular "As" will not work.
How to you approch/resolve this issue ? Is there a pattern addressing this issue ?
PD : my question is for a final C# implementation but maybe the solution is more broad.
Aucun commentaire:
Enregistrer un commentaire