How does one share temporary objects across component graphs executed at different times?
I have a state engine from some old legacy code. Each state is represented by an IState and is responsible for creating the next state in a process.
public interface IState
{
Guid Session { get; }
IState GetNextState();
}
The starting state is initialized by a model:
public class Model
{
private readonly IStateFactory _stateFactory;
public Model(IStateFactory stateFactory)
{
_stateFactory = stateFactory;
}
public IState GetFirstState()
{
return _stateFactory.GetStateA();
}
}
Each state contains a session context (simplified to only contain a GUID here).
public class Context : IDisposable
{
public static int CreatedCount = 0;
public static int DisposedCount = 0;
//Has other DI injected dependencies.
public Context()
{
CreatedCount++;
}
public Guid SessionGuid { get; } = Guid.NewGuid();
public void Dispose()
{
DisposedCount++;
}
}
The "CreatedCount" and "DisposedCount" have been added to assist in demonstrating the problem. Note that they are static ints.
An implementation of a State might be as such:
public class MyState : IState
{
private readonly Context _context;
private readonly IStateFactory _stateFactory;
public MyState(IStateFactory stateFactory, Context context)
{
_context = context;
_stateFactory = stateFactory;
}
public Guid Session => _context.SessionGuid;
public IState GetNextState()
{
var nextState = _stateFactory.GetStateB(_context);
_stateFactory.DestroyState(this);
return nextState;
}
}
The state factory is a simple Castle Windsor implemented TypedFactory interface.
public interface IStateFactory
{
IState GetFirstState();
IState GetStateB(Context context);
void DestroyState(IState state);
}
The idea is that each "state" can initiate the next state based on some action, and that the current states "context" should be used in the next state.
The container is built in the expected way:
var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(
Component.For<Context>().LifestyleTransient(),
Component.For<IState>().ImplementedBy<MyState>().Named("stateA").LifestyleTransient(),
Component.For<IState>().ImplementedBy<MyState>().Named("stateB").LifestyleTransient(),
Component.For<IStateFactory>().AsFactory()
);
Essentially, I want "stateB" to take ownership of the Context. But when I release "stateA" (through a call to MyState.GetNextState), the Context is released and disposed! How do I tell Castle.Windsor to transfer ownership to the next state?
var model = container.Resolve<Model>();
var initialState = model.GetFirstState();
var nextState = initialState.GetNextState(); //releases the initial State.
Assert.That(initialState.Session, Is.EqualTo(nextState.Session)); //The context was 'shared' by stateA by passing it into the factory method for stateB.
Assert.That(Context.CreatedCount, Is.EqualTo(1));
Assert.That(Context.DisposedCount, Is.EqualTo(0)); //FAIL! Castle Windsor should see that the shared "Context" was passed into the constructor of modelB, and added a reference to it.
container.Release(model);
container.Release(nextState); //usually done by the model.
Assert.That(Context.CreatedCount, Is.EqualTo(1));
Assert.That(Context.DisposedCount, Is.EqualTo(1));
It should be noted that state transition can be initiated from another thread, but invoked on the creating thread. This messes up the CallContext used by the default Castle Windsor scoped lifestyle. This is for a desktop application so the default WCF and web-request scope lifestyles do not apply.
Use LifestyleScoped:
Component.For<Context>().LifestyleScoped()
using (container.BeginScope())
{
var model = container.Resolve<Model>();
var initialState = model.GetFirstState();
var nextState = initialState.GetNextState();
Assert.That(Context.CreatedCount, Is.EqualTo(0));
}
Assert.That(Context.CreatedCount, Is.EqualTo(1));
I've come up with another solution to this problem that works where Castle Windsors scope does not. I've created a lifestyle that keeps a singleton around only as long as something is using it by using a reference count. Once the reference count goes to 0, the object is released.
public class ReferenceCountedSingleton : AbstractLifestyleManager, IContextLifestyleManager
{
private readonly object _lock = new object();
private Burden _cachedBurden;
private int _referenceCount;
public override void Dispose()
{
var localInstance = _cachedBurden;
if (localInstance != null)
{
localInstance.Release();
_cachedBurden = null;
}
}
public override object Resolve(CreationContext context, IReleasePolicy releasePolicy)
{
lock(_lock)
{
_referenceCount++;
if (_cachedBurden != null)
{
Debug.Assert(_referenceCount > 0);
return _cachedBurden.Instance;
}
if (_cachedBurden != null)
{
return _cachedBurden.Instance;
}
var burden = CreateInstance(context, false);
_cachedBurden = burden;
Track(burden, releasePolicy);
return burden.Instance;
}
}
public override bool Release(object instance)
{
lock (_lock)
{
if (_referenceCount > 0) _referenceCount--;
if (_referenceCount > 0) return false;
_referenceCount = 0;
_cachedBurden = null;
return base.Release(instance);
}
}
protected override void Track(Burden burden, IReleasePolicy releasePolicy)
{
burden.RequiresDecommission = true;
base.Track(burden, releasePolicy);
}
public object GetContextInstance(CreationContext context)
{
return context.GetContextualProperty(ComponentActivator);
}
}
It is used like this:
container.Register(Component.For<Context>).LifestyleCustom<ReferenceCountedSingleton>());
Related
I have an application which uses a external library to create a client instance for a Db Provider.
This dependency is added as Singleton to my app DI container, and have some parameters which are passed from my app to the initialization constructor of the library.
I need to create another client with different arguments, theoretically can this be achieved?
By my knowledge is that I have to add another singleton class with different arguments to the DI (I am using .NET core IServiceScopeFactory), but how I can resolve the one I need, if both have the same Types.
you can register Provider Factory as singleton
then use it to create your clients
public class DBProviderFactory
{
private static ClientType _clientA { get; set; }
private static ClientType _clientB { get; set; }
private static readonly object ThreadLock = new object();
public ClientType GetInstanceA()
{
if (_clientA != null)
{
return _clientA;
}
lock (ThreadLock)
{
_clientA = new DbInitializer("1", "2");
}
return _clientA;
}
public ClientType GetInstanceB()
{
if (_clientB != null)
{
return _clientA;
}
lock (ThreadLock)
{
_clientB = new DbInitializer("3", "4");
}
return _clientB;
}
}
first register it
services.AddSingleton<DBProviderFactory>();
then use it as below
public class service
{
private ClientType client { get; set; }
public service(DBProviderFactory dBProviderFactory)
{
client = dBProviderFactory.GetInstanceA();
}
}
I have an object that only initializes itself with barebones data when constructed (fast), and loads itself for real (slow) when first accessed. The idea is that I'm creating a lot of these barebones objects at startup and hash them into a map, then fully load each object whenever it is individually accessed for the first time. The problem is that I cannot guarantee how clients will interact with this object, there are multiple public methods that might be invoked.
Is there a good pattern to support this kind of situation? The obvious (and my current) solution is to track state with an internal bool, check against that bool in every function that might be invoked, and load that way. But that requires code duplication of that behavior across all public functions, and is vulnerable to errors.
I can imagine a single point-of-entry method that then dishes out behaviors based on a client request type etc., but before I go consider going down that road I want to see if there's a commonly accepted approach/pattern that I might not be aware of. I'm doing this in C#, but any insight is appreciated.
If I understood what you want to achieve, you are looking for the Proxy Design Pattern, more specifically, a virtual Proxy.
Refer to http://www.dofactory.com/net/proxy-design-pattern
A small example would be something like:
public abstract class IObjectProvider
{
public abstract IObjectProvider Object{get;}
public abstract void doStuff();
}
public class RealObject : IObjectProvider
{
public RealObject()
{
//Do very complicated and time taking stuff;
}
public override IObjectProvider Object
{
get { return this; }
}
public override void doStuff()
{
//do this stuff that these objects normally do
}
}
public class ObjectProxy : IObjectProvider
{
private IObjectProvider objectInstance = null;
public override IObjectProvider Object
{
get
{
if (objectInstance == null)
objectInstance = new RealObject();
return objectInstance;
}
}
public override void doStuff()
{
if(objectInstance!=null)
objectInstance.doStuff();
}
}
public class SkeletonClass
{
public IObjectProvider Proxy1 = new ObjectProxy();
public IObjectProvider Proxy2 = new ObjectProxy();
}
static void Main(String[] args)
{
//Objects Not Loaded
SkeletonClass skeleton = new SkeletonClass();
//Proxy1 loads object1 on demand
skeleton.Proxy1.Object.doStuff();
//Proxy2 not loaded object2 until someone needs it
}
Here's an example of dynamic proxy approach.
using System;
using System.Diagnostics;
using Castle.DynamicProxy; //Remember to include a reference, too. It's nugettable package is Castle.Core
namespace ConsoleApp
{
public class ActualClass
{
//Have static instances of two below for performance
private static ProxyGenerator pg = new ProxyGenerator();
private static ActualClassInterceptor interceptor = new ActualClassInterceptor();
//This is how we get ActualClass items that are wrapped in the Dynamic Proxy
public static ActualClass getActualClassInstance()
{
ActualClass instance = new ActualClass();
return pg.CreateClassProxyWithTarget<ActualClass>(instance, interceptor);
}
//Tracking whether init has been called
private bool initialized = false;
//Will be used as evidence of true initialization, i.e. no longer null
private int? someValue = null;
public void Initialize()
{
if (!initialized)
{
//do some initialization here.
someValue = -1; //Will only get set to non-null if we've run this line.
initialized = true;
}
}
//Any methods you want to intercept need to be virtual!
public virtual int replaceValue(int value)
{
//below will blow up, if someValue has not been set to -1 via Initialize();
int oldValue = someValue.Value;
someValue = value;
return oldValue;
}
//block off constructor from public to enforce use of getActualClassInstance
protected ActualClass() { }
}
public class ActualClassInterceptor : ActualClass, IInterceptor
{
public void Intercept(IInvocation invocation)
{
//Call initialize before proceeding to call the intercepted method
//Worth noting that this is the only place we actually call Initialize()
((ActualClass)invocation.InvocationTarget).Initialize();
invocation.Proceed();
}
}
class Program
{
static void Main(string[] args)
{
ActualClass instance1 = ActualClass.getActualClassInstance();
ActualClass instance2 = ActualClass.getActualClassInstance();
int x1 = instance1.replaceValue(41);
int x2 = instance2.replaceValue(42);
int y1 = instance1.replaceValue(82);
Debug.Assert(y1 == 41);
int y2 = instance2.replaceValue(84);
Debug.Assert(y2 == 42);
var read = Console.ReadKey();
}
}
}
I am new to the state pattern implementation in C#, could you provide some info on how you implement it.
I am refactoring a state machine in C# using the state pattern. Currently my state machine contains 5 states and it is only possible to go forward or backward througout the states,i.e. from state 1 you need to go to state 2, 3 and 4 to finally arrive to state 5.
I am able to go forward just doing
mainclass.State = new NextSate();
which creates a new state every time you want to go forward, however, once all of them have been created and/or you want to go backward I would need to go to the same states, not just a new one. How can I do that? Is there any better way to do it simple?
Strictly speaking, if you're implementing the classic GoF State pattern then the State subclasses themselves are responsible for knowing about and performing the State transitions. The holder of the State isn't responsible for managing the transitions and a large part of the intent of the pattern is to encapsulate the state transition behaviour in the State objects and thus for the client to delegate to them. I've introduced a Factory that ensures that there is only ever a single instance of each State subclass to ensure that the same instance is reused when moving back and forth through the states.
public abstract class State
{
protected StateFactory _factory;
protected IStateUser _context;
public State(StateFactory factory, IStateUser context)
{
_factory = factory;
_context = context;
}
protected void TransitionTo<T>(Func<T> creator) where T : State
{
State state = _factory.GetOrCreate<T>(creator);
_context.CurrentState = state;
}
public abstract void MoveNext();
public abstract void MovePrevious();
}
public class State1 : State
{
public State1(StateFactory factory, IStateUser context)
: base(factory, context)
{
}
public override void MoveNext()
{
TransitionTo<State2>(() => new State2(_factory, _context));
}
public override void MovePrevious()
{
throw new InvalidOperationException();
}
}
public class State2 : State
{
public State2(StateFactory factory, IStateUser context)
: base(factory, context)
{
}
public override void MoveNext()
{
TransitionTo<State3>(() => new State3(_factory, _context)); //State 3 is omitted for brevity
}
public override void MovePrevious()
{
TransitionTo<State1>(() => new State1(_factory, _context));
}
}
public interface IStateUser
{
State CurrentState { get; set; }
}
public class Client : IStateUser
{
public Client()
{
var factory = new StateFactory();
var first = new State1(factory, this);
CurrentState = factory.GetOrCreate<State1>(() => first);
}
public void MethodThatCausesTransitionToNextState()
{
CurrentState.MoveNext();
}
public void MethodThatCausesTransitionToPreviousState()
{
CurrentState.MovePrevious();
}
public State CurrentState
{
get;
set;
}
}
public class StateFactory
{
private Dictionary<string, State> _states = new Dictionary<string, State>();
public State GetOrCreate<T>(Func<T> creator) where T : State
{
string typeName = typeof(T).FullName;
if (_states.ContainsKey(typeName))
return _states[typeName];
T state = creator();
_states.Add(typeName, state);
return state;
}
}
Use internal stack to maintain the previous states:
public class MyClass
{
private Stack<State> _states;
private State _currentState;
public void GoToNextState()
{
// If Not last state then
_states.Push(_currentState);
_currentState = new NextState();
}
public void GoToPrevState()
{
// if not the first state
_currentState = _states.Pop();
}
}
if you want to maintain forward and backward states then create additional stack:
public class MyClass
{
private readonly Stack<State> _nextStates = new Stack<State>();
private readonly Stack<State> _prevStates = new Stack<State>();
private State _currentState = new SampleState1();
public State CurrentState { get { return _currentState; } }
public void GoToNextState()
{
if (_currentState.NextState == null)
return;
_prevStates.Push(_currentState);
_currentState = _nextStates.Count > 0 ? _nextStates.Pop() : _currentState.NextState;
}
public void GoToPrevState()
{
// if not the first state
_nextStates.Push(_currentState);
_currentState = _prevStates.Pop();
}
}
Do you have a state manager of some kind? If so, that one could hold the state instances. By decoupling the state transition knowledge from the states themselves, you let the manager decide on the transition. The manager will inspect the state that requested the transition: it determines it is the "step 1" state, and returns (or creates) the "state 2" state.
I'm trying to fix a garbage collection problem of a MVVM application which uses the following model of Undo stack.
The example is very minimalistic and real world code is much different, uses a factory class of undo lists per ViewModel instead of a single undolist but is representative:
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Reflection;
using System.ComponentModel;
using System.Linq;
namespace ConsoleApplication9
{
public class UndoList
{
public bool IsUndoing { get; set; }
private Stack<Action> _undo = new Stack<Action>();
public Stack<Action> Undo
{
get { return _undo; }
set { _undo = value; }
}
private static UndoList _instance;
// singleton of the undo stack
public static UndoList Instance
{
get
{
if (_instance == null)
{
_instance = new UndoList();
}
return _instance;
}
}
}
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
// execute the last undo operation
public void Undo()
{
UndoList.Instance.IsUndoing = true;
var action = UndoList.Instance.Undo.Pop();
action();
UndoList.Instance.IsUndoing = false;
}
// push an action into the undo stack
public void AddUndo(Action action)
{
if (UndoList.Instance.IsUndoing) return;
UndoList.Instance.Undo.Push(action);
}
// create push an action into the undo stack that resets a property value
public void AddUndo(string propertyName, object oldValue)
{
if (UndoList.Instance.IsUndoing) return;
var property = this.GetType().GetProperties().First(p => p.Name == propertyName);
Action action = () =>
{
property.SetValue(this, oldValue, null);
};
UndoList.Instance.Undo.Push(action);
}
}
public class TestModel : ViewModel
{
private bool _testProperty;
public bool TestProperty
{
get
{
return _testProperty;
}
set
{
base.AddUndo("TestProperty", _testProperty);
_testProperty = value;
}
}
// mock property indicating if a business action has been done for test
private bool _hasBusinessActionBeenDone;
public bool HasBusinessActionBeenDone
{
get
{
return _hasBusinessActionBeenDone;
}
set
{
_hasBusinessActionBeenDone = value;
}
}
public void DoBusinessAction()
{
AddUndo(() => { inverseBusinessAction(); });
businessAction();
}
private void businessAction()
{
// using fake property for brevity of example
this.HasBusinessActionBeenDone = true;
}
private void inverseBusinessAction()
{
// using fake property for brevity of example
this.HasBusinessActionBeenDone = false;
}
}
class Program
{
static void Test()
{
var vm = new TestModel();
// test undo of property
vm.TestProperty = true;
vm.Undo();
Debug.Assert(vm.TestProperty == false);
// test undo of business action
vm.DoBusinessAction();
vm.Undo();
Debug.Assert(vm.HasBusinessActionBeenDone == false);
// do it once more without Undo, so the undo stack has something
vm.DoBusinessAction();
}
static void Main(string[] args)
{
Program.Test();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
// at this point UndoList.Instance.Undo
// contains an Action which references the TestModel
// which will never be collected...
// in real world code knowing when to clear this is a problem
// because it is a singleton factory class for undolists per viewmodel type
// ideally would be to clear the list when there are no more references
// to the viewmodel type in question, but the Actions in the list prevent that
}
}
}
You see that when any viewModel goes out of scope the actions in the UndoList keep references to them. The real code groups various viewmodels into grouped undolists (viewModels that contain child viewmodels share the same undo stack), so it is difficult to know when and where to put the clearing.
I was wondering if there is some method to make those actions expire if they are the only one keeping references to the variables inside them?
Suggestions welcome!
I've got a solution for you. I don't like the use of the UndoList as a singleton, but I've kept it to provide you with a direct answer to your question. In practice I wouldn't use a singleton.
Now, you will find it very difficult to avoid capturing references to your view models in your actions. It would make your code very ugly if you tried. The best approach is to make your view models implement IDisposable and make sure that you dispose of them when they go out of scope. Remember that the garbage collector never calls Dispose so you must.
Using IDisposable is the standard model for cleaning up when an
instance is no longer needed.
So the first thing to define is a helper class that executes an action when it is disposed.
public sealed class AnonymousDisposable : IDisposable
{
private readonly Action _dispose;
private int _isDisposed;
public AnonymousDisposable(Action dispose)
{
_dispose = dispose;
}
public void Dispose()
{
if (Interlocked.Exchange(ref _isDisposed, 1) == 0)
{
_dispose();
}
}
}
Now I can write things like this to remove elements from lists:
var disposable = new AnonymousDisposable(() => list.Remove(item));
Later, when I call disposable.Dispose() the item is removed from the list.
Now here's your code re-implemented.
I've changed UndoList to be a static class, not a singleton. You can change it back if need be.
public static class UndoList
{
public static bool IsUndoing { get; private set; }
private static List<Action> _undos = new List<Action>();
public static IDisposable AddUndo(Action action)
{
var disposable = (IDisposable)null;
if (!IsUndoing)
{
disposable = new AnonymousDisposable(() => _undos.Remove(action));
_undos.Add(action);
}
return disposable ?? new AnonymousDisposable(() => { });
}
public static bool Undo()
{
IsUndoing = true;
var result = _undos.Count > 0;
if (result)
{
var action = _undos[_undos.Count - 1];
_undos.Remove(action);
action();
}
IsUndoing = false;
return result;
}
}
You'll notice that I've replaced the stack with a list. I did that because I need to remove items from inside the list.
Also, you can see that AddUndo now returns an IDisposable. Calling code needs to keep the return disposable and call Dispose when it wants to remove the action from the list.
I've also internalized the Undo action. It didn't make sense to have it in the view model. Calling Undo effectively pops the top item off of the list and executes the action and returns true. However, if the list is empty it returns false. You can use this for testing purposes.
The ViewModel class now looks like this:
public class ViewModel : IDisposable, INotifyPropertyChanged
{
public ViewModel()
{
_disposables = new List<IDisposable>();
_disposable = new AnonymousDisposable(() =>
_disposables.ForEach(d => d.Dispose()));
}
private readonly List<IDisposable> _disposables;
private readonly IDisposable _disposable;
public void Dispose()
{
_disposable.Dispose();
}
public event PropertyChangedEventHandler PropertyChanged;
protected void AddUndo(Action action)
{ ... }
protected void SetUndoableValue<T>(Action<T> action, T newValue, T oldValue)
{ ... }
}
It implements IDisposable and internally, keeps track of a list of disposables and an anonymous disposable that will dispose of the items in the list when the view model itself is disposed of. Whew! A mouthful, but I hope that makes sense.
The AddUndo method body is this:
protected void AddUndo(Action action)
{
var disposable = (IDisposable)null;
Action inner = () =>
{
_disposables.Remove(disposable);
action();
};
disposable = UndoList.AddUndo(inner);
_disposables.Add(disposable);
}
Internally it calls UndoList.AddUndo passing in an action that will remove the returned IDisposable from the view model's list of undo actions when UndoList.Undo() is called - as well as, importantly, actually executing the action.
So this means that when the view model is disposed all of its outstanding undo actions are removed from the undo list and when Undo is called the associated disposable is removed from the view model. And this ensures that you are not keeping references to the view model when it is disposed of.
I created a helper function called SetUndoableValue that replaced your void AddUndo(string propertyName, object oldValue) method which wasn't strongly-typed and could cause you to have run-time errors.
protected void SetUndoableValue<T>(Action<T> action, T newValue, T oldValue)
{
this.AddUndo(() => action(oldValue));
action(newValue);
}
I made both of these methods protected as public seemed too promiscuous.
The TestModel is more-or-less the same:
public class TestModel : ViewModel
{
private bool _testProperty;
public bool TestProperty
{
get { return _testProperty; }
set
{
this.SetUndoableValue(v => _testProperty = v, value, _testProperty);
}
}
public bool HasBusinessActionBeenDone { get; set; }
public void DoBusinessAction()
{
this.AddUndo(this.inverseBusinessAction);
businessAction();
}
private void businessAction()
{
this.HasBusinessActionBeenDone = true;
}
private void inverseBusinessAction()
{
this.HasBusinessActionBeenDone = false;
}
}
And finally, here's the code that tests the UndoList functions correctly:
using (var vm = new TestModel())
{
Debug.Assert(UndoList.Undo() == false);
vm.TestProperty = true;
Debug.Assert(UndoList.Undo() == true);
Debug.Assert(UndoList.Undo() == false);
Debug.Assert(vm.TestProperty == false);
vm.DoBusinessAction();
Debug.Assert(UndoList.Undo() == true);
Debug.Assert(vm.HasBusinessActionBeenDone == false);
vm.DoBusinessAction();
}
Debug.Assert(UndoList.Undo() == false);
Please let me know if I can provide any more detail on anything.
If you can't clean it up any other way you could use WeakReference to hold property, but I think there would be other issues because this would still cause a Action instance to exist with a null reference attached to it.
As a quick look I would be more inclined to use the singleton to hold a registration to the model and let the model manage a instance list of all the undo actions attached to it. When the model goes out of scope call a clean-up method on it or implement a IDisposable type interface on it may if this fits. However depending on the implementation you may not need the singleton anyway.
We are currently using the decorator design pattern to perform some caching. So we have a bunch of classes that look something like this:
interface IComponent
{
object Operation();
object AnotherOperation();
}
public ConcreteComponentA : IComponent
{
public object Operation()
{
return new object();
}
public object AnotherOperation()
{
return new object();
}
}
public ConcreteDecoratorA : IComponent
{
protected IComponent component;
public object Operation()
{
if(!this.cache.Contains("key")
{
this.cache["key"] = this.component.Operation();
}
return this.cache["key"];
}
So if a client wanted to use caching they would create a new ConcreteDecoratorA and pass in a ConcreteComponentA to the constructor. The problem we are facing is, imagine that AnotherOperation() requires a call to Operation in order to do it's work. ConcreteComponentA might now look something like this:
public ConcreteComponentA : IComponent
{
public object Operation()
{
return new object();
}
public object AnotherOperation()
{
object a = this.Operation();
// Do some other work
return a;
}
}
The problem is that when calling Operation() method from within AnotherOperation() method, the decorator implementation will never be called, because obviously the decorator is not in the inheritance hierarchy of ConcreteComponentA.
So have we made a poor design decision somewhere or is this just a limitation of the decorator design pattern that we have to accept?
Note that in my real world example, ConcreteComponentA is a wrapper to a third party system that we do not have control over. We have developed IComponent and a bunch of POCOs that we work with to abstract away that third party system. In this case we have to make two calls to their system in order to get the data required, it's just about where we make those two calls.
You could create an overload of AnotherOperation which takes the IComponent to be used as a parameter.
public ConcreteComponentA : IComponent
{
public object Operation()
{
return new object();
}
public object AnotherOperation()
{
return AnotherOperation(this);
}
public object AnotherOperation(IComponent comp)
{
object a = comp.Operation();
// Do some other work
return a;
}
}
public ConcreteDecoratorA : IComponent
{
protected IComponent component;
public object Operation()
{
if(!this.cache.Contains("key")
{
this.cache["key"] = this.component.Operation();
}
return this.cache["key"];
}
public object AnotherOperation()
{
return this.component.AnotherOperation(this);
}
}
Create a delegate (or an event if you want to support multiple decorators) that allows decorators to manually "override" the Operation method.
public class ConcreteComponentA : IComponent
{
public event Func<object> OperationOverride;
public object Operation()
{
if (OperationOverride != null)
{
return OperationOverride();
}
return new object();
}
public object AnotherOperation()
{
var a = Operation();
// Do some other work
return a;
}
}
In the decorator constructor attempt to cast the component instance into your concrete component type and attach an Operation override delegate.
public class ConcreteDecoratorA : IComponent, IDisposable
{
protected readonly IComponent component;
public ConcreteDecoratorA(IComponent component)
{
this.component = component;
AttachOverride();
}
public void Dispose()
{
DetachOverride();
}
private void AttachOverride()
{
var wrapper = component as ConcreteComponentA;
if (wrapper != null)
{
wrapper.OperationOverride += Operation;
}
}
private void DetachOverride()
{
var wrapper = component as ConcreteComponentA;
if (wrapper != null)
{
wrapper.OperationOverride -= Operation;
}
}
}
Use the disposable pattern to ensure that the event is unhooked when the decorator is no longer needed to prevent memory leaks.
Self-calls are the limitation of decorator design pattern, that's true.
The only way to intercept base component self-calls without having to modify it or add any additional infrastructure is inheritance. So if you don't like solutions from above and you still want to have the flexibility which decorator gives you (possibility of having any number and any order of decorators), you can look for an implementation of dynamic proxy that generates subtypes (i.e. Unity Interception, Castle Dynamic Proxy).
I prefer to use inheritance rather than encapsulation to do my caching, this way, the cached value will use the caching method because it's virtual:
public ConcreteComponentA : IComponent
{
public virtual object Operation()
{
return new object();
}
public object AnotherOperation()
{
object a = this.Operation();
// Do some other work
return a;
}
}
public CachingComponentA : ConcreteComponentA
{
public override object Operation()
{
if(!this.cache.Contains("key")
{
this.cache["key"] = base.Operation();
}
return this.cache["key"];
}
}
Then when you're using a decorator object, this.Operation() WILL use the decorator class.
Since you have control over both levels (ConcreteComponentA and ConcreteDecoratorA), you can have them hand notes back and forth:
interface IComponent
{
Action<object> myNotify;
object Operation(); object AnotherOperation();
}
public ConcreteComponentA : IComponent
{
public Action<object> myNotify = null;
public object Operation()
{
object result = new object();
if (myNotify != null)
{
myNotify(result);
}
return result;
}
public object AnotherOperation()
{
return Operation();
}
}
public ConcreteDecoratorA : IComponent
{
public ConcreteDecoratorA(IComponent target)
{
component = target;
target.myNotify = notifyMe;
}
protected IComponent component;
protected notifyMe(object source)
{
this.cache["key"] = source;
}
public Action<object> myNotify = null;
public object Operation()
{
if(!this.cache.Contains("key")
{
return component.Operation();
}
return this.cache["key"];
}
public object AnotherOperation()
{
}
}