I understand the Decorator pattern, in it's simplest terms. The idea being that one class wraps another, where a decorator method wishes to run some other code before and/or after calling the same method on the decorated object.
However, I have run into the situation where I cannot simply call the decorated method, as it has some undesired side-effects. However I do want much of that decorated method to run.
So I believe that I need to split the decorated method into multiple methods, then in the decorator I can call some of them, run my decorating code, then call some others - missing out the side-effect I don't want.
However in order to maintai开发者_运维知识库n polymorphism, that would mean adding those methods to the interface that the decorated and decorator objects implement. This is undesirable; they should not be public, and it effectively means the decorated class has knowledge of how it will be decorated.
I believe that the Template pattern is possibly more appropriate, where an abstract base class calls each of the smaller methods in turn, where the "decorator" simply supplies an alternative implementation for the ones it cares about. However this isn't exactly "composition over inheritance", so what do you recommend?
Sounds like Template suits your scenario best. I wouldn't force composition when not needed ... this conversation said it best, "...exceptions to this rule: when you should use inheritance i.e. if you need to model substitutability."
It sounds like your API violates Command-Query Separation so your best option would be to redesign the API.
However, in case I'm mistaken or redesign is not possible, perhaps you could split the method of the decorated class into two methods without changing the interface.
public interface IMyInterface
{
Foo GetFoo(Bar bar);
}
public class MyClass : IMyInterface
{
public Foo GetFoo(Bar bar)
{
this.DoSomethingWithSideEffects(bar);
return this.DoSomethingToGetFoo(bar);
}
public Foo DoSomethingToGetFoo(Bar bar)
{
// ...
}
public void DoSomethingWithSideEffects(Bar bar)
{
// ...
}
}
public class MyDecorator : IMyInterface
{
private readonly MyClass mc;
public MyDecorator(MyClass mc)
{
// put Null Guard here...
this.mc = mc;
}
public Foo GetFoo(Bar bar)
{
return this.mc.DoSomethingToGetFoo(bar);
}
}
Notice that MyDecorator decorates MyClass instead of IMyInterface.
精彩评论