State Pattern C# with previous states - c#

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.

Related

Observer pattern implementation with complete layer separation and testability, am I doing it right?

I have doubts regarding my implementation of observer pattern, but with complete separation of concerns.
Example below is not a real life code, but just an example of idea how I want to do it.
In my solution I have two project layers:
Desktop layer (views, view models, models)
Service library layer (with observers)
My view model is a subject subscribing the observers.
Code in VM:
interface ISubject
{
void Subscribe(IObserverService observer);
void Unsubscribe(IObserverService observer);
void Notify();
}
public class MainWindowViewModel : ViewModelBase, ISubject
{
private readonly IObserverService _observer1;
private readonly IObserverService _observer2;
private ArrayList _observers;
public MainWindowViewModel(
IObserver1 observer1,
IObserver2 observer2)
{
_observer1 = observer1;
_observer2 = observer2;
ObserverCommand = new DelegateCommand(OnObserverCommand);
InitProgram();
}
private void InitProgram()
{
_observers = new ArrayList();
_observers.Add(_observer1);
_observers.Add(_observer2);
}
public List<IObserverService> Observers { get; set; }
private void OnSwitchCommand(object obj)
{
if (Jeden == true)
{
UiModel = _controlsService.SwitchOff();
}
else
{
UiModel = _controlsService.SwitchOn();
}
}
private void OnObserverCommand(object obj)
{
SomeValue++;
}
public void Subscribe(IObserverService observer)
{
Observers.Add(observer);
}
public void Unsubscribe(IObserverService observer)
{
Observers.Remove(observer);
}
public void Notify()
{
Observers.ForEach(x => x.Update(SomeValue));
}
public ICommand ObserverCommand { get; private set; }
private int _someValue;
public int SomeValue
{
get => _someValue;
set
{
_someValue = value;
InformObservers();
}
}
private void InformObservers()
{
foreach (IObserverService x in _observers)
{
x.Update(SomeValue);
}
}
}
And my observer in service layer is very simple. After Update call from the subject is displaying new MessageBox:
public interface IObserverService
{
void Update(int someValue);
}
public class Observer1 : IObserver1, IObserverService
{
public string ObserverName { get; private set; }
public Observer1(string name)
{
this.ObserverName = name;
}
public void Update(int someValue)
{
MessageBox.Show("New value: " + someValue.ToString() + " for " + ObserverName);
}
}
Observer2 is same as above.
Right now I have doubts how my constructor supposed to look like, if I want to create a new observer with a name parameter, for example: new Observer1("name1") in this case, keeping separation, should my subject's ctor look like:
public MainWindowViewModel()
{
_observerService = observerService;
IObserverService observer1 = new ObserverService("name1");
IObserverService observer2 = new ObserverService("name2");
SwitchCommnad = new DelegateCommand(OnSwitchCommand);
ObserverCommand = new DelegateCommand(OnObserverCommand);
InitProgram();
}
Is it correct approach? Is it going to be testable? Or I have to inject IObserverService somehow?
If you want to test your VM, follow IoC and don't create your ObserverServices inside it but as you say, inject IObserverService; therefore you'll be able to mock the services and test your VM without needing the whole service behavior.
I may suggest you to use Autofac or even Ninject. There are plenty of DI frameworks so look for the one that adjust to what you are looking for.
it makes sense, that MainWindowViewModel will receive some external observers via constructor:
public MainWindowViewModel(IObserver1 observer1, IObserver2 observer2)
{
_observer1 = observer1;
_observer2 = observer2;
ObserverCommand = new DelegateCommand(OnObserverCommand);
InitProgram();
}
when you create an instance of MainWindowViewModel (I assume, it will be used for MainWindowView DataContext), you will pass some real observers:
IObserverService observer1 = new ObserverService("name1");
IObserverService observer2 = new ObserverService("name2");
var vm = new MainWindowViewModel(observer1, observer2);
mainWindow.DataContext = vm;
no need for DI container here if dependencies can be resolved statically
similarly, for test you can have some TestObserverService (or IObserverService mock):
IObserverService observer1 = new TestObserverService("name1");
IObserverService observer2 = new TestObserverService("name2");
var vm = new MainWindowViewModel(observer1, observer2);
MainWindowViewModel might create some IObserverServices, if it has properties worth observing from other objects in the application (e.g. related view models)

Castle Windsor explicitly sharing dependencies

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>());

How to encapsulate .NET Stateless state machine

I have a project where there is a mostly linear workflow. I'm attempting to use the .NET Stateless library to act as workflow engine/state machine. The number of examples out there is limited, but I've put together the following code:
private StateMachine<WorkflowStateType, WorkflowStateTrigger> stateMachine;
private StateMachine<WorkflowStateType, WorkflowStateTrigger>.TriggerWithParameters<Guid, DateTime> registrationTrigger;
private Patient patient;
public Patient RegisterPatient(DateTime dateOfBirth)
{
configureStateMachine(WorkflowState.Unregistered);
stateMachine.Fire<DateTime>(registrationTrigger, dateOfBirth);
logger.Info("State changed to: " + stateMachine.State);
return patient;
}
private void configureStateMachine(WorkflowState state)
{
stateMachine = new StateMachine<WorkflowState, WorkflowTrigger>(state);
registrationTrigger = stateMachine.SetTriggerParameters<DateTime>(WorkflowTrigger.Register);
stateMachine.Configure(WorkflowState.Unregistered)
.Permit(WorkflowTrigger.Register, WorkflowStateType.Registered);
stateMachine.Configure(WorkflowState.Registered)
.Permit(WorkflowTrigger.ScheduleSampling, WorkflowState.SamplingScheduled)
.OnEntryFrom(registrationTrigger, (dateOfBirth) => registerPatient(dateOfBirth));
}
private void registerPatient(DateTime dateOfBirth)
{
//Registration code
}
As you can see, I'm using the Stateless Fire() overload that allows me to pass in a trigger. This is so I can have the state machine process business logic, in this case, code to register a new patient.
This all works, but now I'd like to move all the state machine code into another class to encapsulate it and I'm having trouble doing this. The challenges I've had in doing this are:
instantiating a StateMachine object requires you to specify state and State is a readonly property that can only be set at instantiation.
my registrationTrigger has to be instantiated during state machine configuration and also has to be available by the calling class.
How can I overcome these items and encapsulate the state machine code?
There is an article by Scott Hanselman with an example and introduction to a library. Also there few examples available on their GitHub including Bug implementation example mentioned in Scott's article that encapsulates the state machine.
Below is an example of how the state can be extracted from behavior:
public class PatientRegistrationState
{
private StateMachine<WorkflowState, WorkflowTrigger> stateMachine;
private StateMachine<WorkflowState, WorkflowStateTrigger>.TriggerWithParameters<DateTime> registrationTrigger;
public PatientRegistrationState(State initialState = default(State)) {
stateMachine = new StateMachine<WorkflowState, WorkflowTrigger>(initialState);
stateMachine.Configure(WorkflowState.Unregistered)
.Permit(WorkflowTrigger.Register, WorkflowStateType.Registered);
stateMachine.Configure(WorkflowState.Registered)
.Permit(WorkflowTrigger.ScheduleSampling, WorkflowState.SamplingScheduled)
.OnEntryFrom(registrationTrigger, (date) => OnPatientRegistered(date));
}
public WorkflowState State => stateMachine.State;
public Action<DateTime> OnPatientRegistered {get; set;} = (date) => { };
// For state changes that do not require parameters.
public void ChangeTo(WorkflowTrigger trigger)
{
stateMachine.Fire<DateTime>(trigger);
}
// For state changes that require parameters.
public void ChangeToRegistered(DateTime dateOfBirth)
{
stateMachine.Fire<DateTime>(registrationTrigger, dateOfBirth);
}
// Change to other states that require parameters...
}
public class PatientRegistration
{
private PatientRegistrationState registrationState;
private Patient patient;
public PatientRegistration()
{
registrationState = PatientRegistrationState(WorkflowState.Unregistered)
{
OnPatientRegistered = RegisterPatient;
}
}
public Patient RegisterPatient(DateTime dateOfBirth)
{
registrationState.ChangeToRegistered(dateOfBirth);
logger.Info("State changed to: " + registrationState.State);
return patient;
}
private void RegisterPatient(DateTime dateOfBirth)
{
// Registration code
}
}
This is how I achieved it in my project.
Separated workflow logic to separate class. I had couple of workflows based on one of the flags present in the request object; below is one of the workflow classes:
public class NationalWorkflow : BaseWorkflow
{
public NationalWorkflow(SwiftRequest request) : this(request, Objects.RBDb)
{ }
public NationalWorkflow(SwiftRequest request, RBDbContext dbContext)
{
this.request = request;
this.dbContext = dbContext;
this.ConfigureWorkflow();
}
protected override void ConfigureWorkflow()
{
workflow = new StateMachine<SwiftRequestStatus, SwiftRequestTriggers>(
() => request.SwiftRequestStatus, state => request.SwiftRequestStatus = state);
workflow.OnTransitioned(Transitioned);
workflow.Configure(SwiftRequestStatus.New)
.OnEntry(NotifyRequestCreation)
.Permit(SwiftRequestTriggers.ProcessRequest, SwiftRequestStatus.InProgress);
workflow.Configure(SwiftRequestStatus.InProgress)
.OnEntry(ValidateRequestEligibility)
.Permit(SwiftRequestTriggers.AutoApprove, SwiftRequestStatus.Approved)
.Permit(SwiftRequestTriggers.AdvancedServicesReview, SwiftRequestStatus.PendingAdvancedServices);
.....................
}
Which is triggered from the controller/any other layer:
private static void UpdateRequest(SwiftRequestDTO dtoRequest)
{
var workflow = WorkflowFactory.Get(request);
workflow.UpdateRequest();
}
As mentioned above, I had different workflow rules based on conditions in the request object and hence used a factory pattern WorkflowFactory.Get(request); you may create an instance of your workflow/inject it as desired
And inside the workflow class (BaseWorkflow class in my case), I have exposed the actions:
public void UpdateRequest()
{
using (var trans = this.dbContext.Database.BeginTransaction())
{
this.actionComments = "Updating the request";
this.TryFire(SwiftRequestTriggers.Update);
SaveChanges();
trans.Commit();
}
}
protected void TryFire(SwiftRequestTriggers trigger)
{
if (!workflow.CanFire(trigger))
{
throw new Exception("Cannot fire " + trigger.ToString() + " from state- " + workflow.State);
}
workflow.Fire(trigger);
}

More .net approach for dynamic state machine

I wrote a simple dynamic FSM. Dynamic means the state transitions are dynamic and not static as shown in ConcreteStateB.
namespace FSM_Example
{
using System;
class Program
{
static void Main()
{
var context = new Context(new ConcreteStateA());
context.Run();
Console.Read();
}
}
abstract class State
{
public abstract void Execute(Context context);
}
class ConcreteStateA : State
{
public override void Execute(Context context)
{
context.State = new ConcreteStateB();
}
}
class ConcreteStateB : State
{
public override void Execute(Context context)
{
Console.Write("Input state: ");
string input = Console.ReadLine();
context.State = input == "e" ? null : new ConcreteStateA();
}
}
class Context
{
private State _state;
public Context(State state)
{
State = state;
}
public State State
{
get { return _state; }
set
{
_state = value;
Console.WriteLine("State: " + _state.GetType().Name);
}
}
public void Run()
{
while (_state != null)
{
_state.Execute(this);
}
}
}
}
This implements a state machine as described in GoF305.
Since I'm new to C# and .net: Are there better approaches archieving this goal using more specific features from .net or C#?
Outcoldman's answer provides numerous great options.
Now, I know that the code below is not a proper FSM according to the pattern, but for very simple implementations it could help you avoid writing a lot of extra subclasses. It's just a matter of deciding the right tool for the job. This one mainly focuses around the use of the Action<T> generic delegate:
public class Context
{
public Action<Context> State { get; internal set; }
public Context(Action<Context> state)
{
State = state;
}
public void Run()
{
while (State != null)
{
State(this);
}
}
}
And have the "state machine" as:
public static class SimpleStateMachine
{
public static void StateA(Context context)
{
context.State = StateB;
}
public static void StateB(Context context)
{
Console.Write("Input state: ");
var input = Console.ReadLine();
context.State = input == "e" ? (Action<Context>)null : StateA;
}
}
And for kicking off the process you'd use:
var context = new Context(SimpleStateMachine.StateA);
context.Run();
Console.Read();
Also, for states that aren't related you can use Lambda expressions as well, such as:
Action<Context> process = context =>
{
//do something
context.State = nextContext =>
{
//something else
nextContext.State = null;
};
};
There are plenty approaches which you can apply, but mostly it depends on the task which you need to achieve.
You can use interface instead of abstract class. In C# you cannot inherit more than one class, so it is always good to not take this option from realization.
interface IState
{
void Handle(Context context);
}
You can use generics, so you can write base interfaces / classes for State pattern once and use it everywhere:
abstract class IState<T>
{
void Handle(T context);
}
Next things depend on what do you want to hide or don't want to hide. For example you can probably hide setter for property State, to make sure that nobody can use outside of your dll, so you can make the setter of this property internal.
You can use Async for State Change, something like
interface IState
{
Task HandleAsync(Context context);
}
class Context
{
// ...
public async Task RunAsync()
{
while (_state != null)
{
await _state.HandleAsync(this);
}
}
}
My bet that somebody already implemented it with Rx

A problem when using the decorator design pattern

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()
{
}
}

Categories