I have 2 projects : The first project is a structure project which i read from an xml file.
This project is used in other solutions
The second project(1 of the other solutions) work on the structure project with foreach running on components list:
namespace FriendProject.Workers
{
public class Worker
{
static void Main(string[] args)
{
foreach (Component component in ComponentList)
{
DoWork(component);
}
}
}
}
Today the DoWork method does the following:
public void DoWork(Component component)
{
// Doing work on component properties
// Zip component files with open source Zipper
if (component is DBComponent)
{
// work on DBComponent properties
}
}
Now if you are familiar with design patterns then you can see that there is an injection point here and the following should be done :
public class Component
{
public virtual void DoWork()
{
// Do work
}
}
public class DBComponent : Component
{
public override void DoWork()
{
base.DoWork();
// injection point - work on DBComponent properties
}
}
public class Operator
{
static void Main(string[] args)
{
foreach (Component component in ComponentList)
{
component.DoWork();
}
}
}
The problem is that the project which holds the Component and DBComponent is a structure project which is used in other solutions and with other projects and I need to add the open source Zip dll to the project and it becomes more tightly coupled to the current project("FriendProject") and less usable. Not to talk about that the other projects will never use these methods(DoWork in Component and DBComponent)
Is there a better solution without changing much the design? Should I add an adpater?
If so please provide and example.
Thanks to all
Edit: Short Question
2 projects :
One is a manager project which acts on the second project.
Second is a structure project(read data from xml) which is reused with other projects.
I want to add methods and refernces(since of polymorphism) in the structure project(second project). However it feels wrong since the other projects that uses it will never use those methods and the added references.
Is there a better solution for how to do it?
Edit :
Removed the structure project code the shorten the question. this code was irrelavent since its classes(Component and DBComponent) appear next.
Easy (and with three different GOF design patterns).
Since we can't do anything with the components, we'll have to use the bridge pattern.
Let's define handlers:
public interface IHandlerOf<T> where T : Component
{
void DoWork(T component);
}
So now we can create a handler type for each component type that we want to handle. A DB component handler would look like this:
public class DbComponentHandler : IHandlerOf<DbComponent>
{
public void DoWork(DbComponent component)
{
// do db specific information here
}
}
But since we don't really want to keep track of all handlers we'll want to create a class that does it for us. We ultimately want to invoke the code just as in your example:
foreach (Component component in ComponentList)
{
handler.DoWork(component);
}
But let's make it a bit cooler:
//maps handlers to components
var service = new ComponentService();
// register all handlers in the current assembly
service.Register(Assembly.GetExecutingAssembly());
// fake a component
var dbComponent = new DbComponent();
// the cool part, the invoker doesn't have to know
// about the handlers = facade pattern
service.Invoke(dbComponent);
The service with makes it possible looks like this:
public class ComponentService
{
private readonly Dictionary<Type, IHandlerInvoker> _handlers = new Dictionary<Type, IHandlerInvoker>();
public void Register(Assembly assembly)
{
foreach (var type in assembly.GetTypes())
{
if (type.IsInterface)
continue;
foreach (var interfaceType in type.GetInterfaces())
{
if (!interfaceType.IsGenericType || interfaceType.GetGenericTypeDefinition() != typeof(IHandlerOf<>))
continue;
var componentType = interfaceType.GetGenericArguments()[0];
var instance = Activator.CreateInstance(type);
var method = instance.GetType().GetMethod("DoWork", new[] { componentType });
_handlers[componentType] = new ReflectionInvoker(instance, method);
}
}
}
public void Register<T>(IHandlerOf<T> handler) where T : Component
{
_handlers[typeof (T)] = new DirectInvoker<T>(handler);
}
#region Nested type: DirectInvoker
private class DirectInvoker<T> : IHandlerInvoker where T : Component
{
private readonly IHandlerOf<T> _handler;
public DirectInvoker(IHandlerOf<T> handler)
{
_handler = handler;
}
#region IHandlerInvoker Members
public void Invoke(Component component)
{
_handler.DoWork((T) component);
}
#endregion
}
#endregion
#region Nested type: IHandlerInvoker
private interface IHandlerInvoker
{
void Invoke(Component component);
}
#endregion
#region Nested type: ReflectionInvoker
private class ReflectionInvoker : IHandlerInvoker
{
private readonly object _instance;
private readonly MethodInfo _method;
public ReflectionInvoker(object instance, MethodInfo method)
{
_instance = instance;
_method = method;
}
#region IHandlerInvoker Members
public void Invoke(Component component)
{
_method.Invoke(_instance, new object[] {component});
}
#endregion
}
#endregion
public void Invoke(Component component)
{
IHandlerInvoker invoker;
if (!_handlers.TryGetValue(component.GetType(), out invoker))
throw new NotSupportedException("Failed to find a handler for " + component.GetType());
invoker.Invoke(component);
}
}
Do note that the interface (IHandlerOf<T>) is generic which means that we can't store it directly in a Dictionary. Hence we use the Adapter pattern to store all handlers.
Full example:
public interface IHandlerOf<in T> where T : Component
{
void DoWork(T component);
}
public class ComponentService
{
private readonly Dictionary<Type, IHandlerInvoker> _handlers = new Dictionary<Type, IHandlerInvoker>();
public void Register(Assembly assembly)
{
foreach (var type in assembly.GetTypes())
{
if (type.IsInterface)
continue;
foreach (var interfaceType in type.GetInterfaces())
{
if (!interfaceType.IsGenericType || interfaceType.GetGenericTypeDefinition() != typeof(IHandlerOf<>))
continue;
var componentType = interfaceType.GetGenericArguments()[0];
var instance = Activator.CreateInstance(type);
var method = instance.GetType().GetMethod("DoWork", new[] { componentType });
_handlers[componentType] = new ReflectionInvoker(instance, method);
}
}
}
public void Register<T>(IHandlerOf<T> handler) where T : Component
{
_handlers[typeof (T)] = new DirectInvoker<T>(handler);
}
#region Nested type: DirectInvoker
private class DirectInvoker<T> : IHandlerInvoker where T : Component
{
private readonly IHandlerOf<T> _handler;
public DirectInvoker(IHandlerOf<T> handler)
{
_handler = handler;
}
#region IHandlerInvoker Members
public void Invoke(Component component)
{
_handler.DoWork((T) component);
}
#endregion
}
#endregion
#region Nested type: IHandlerInvoker
private interface IHandlerInvoker
{
void Invoke(Component component);
}
#endregion
#region Nested type: ReflectionInvoker
private class ReflectionInvoker : IHandlerInvoker
{
private readonly object _instance;
private readonly MethodInfo _method;
public ReflectionInvoker(object instance, MethodInfo method)
{
_instance = instance;
_method = method;
}
#region IHandlerInvoker Members
public void Invoke(Component component)
{
_method.Invoke(_instance, new object[] {component});
}
#endregion
}
#endregion
public void Invoke(Component component)
{
IHandlerInvoker invoker;
if (!_handlers.TryGetValue(component.GetType(), out invoker))
throw new NotSupportedException("Failed to find a handler for " + component.GetType());
invoker.Invoke(component);
}
}
public class DbComponent : Component
{
}
public class DbComponentHandler : IHandlerOf<DbComponent>
{
public void DoWork(DbComponent component)
{
// do db specific information here
Console.WriteLine("some work done!");
}
}
internal class Program
{
private static void Main(string[] args)
{
var service = new ComponentService();
service.Register(Assembly.GetExecutingAssembly());
var dbComponent = new DbComponent();
service.Invoke(dbComponent);
}
}
If you're sure you want to split data structure and data operations, create separate worker class.
public interface IWorker
{
void DoWork();
}
public abstract Worker<T>: IWorker where T: Component
{
private T _component;
protected Worker(T component) {_component = component;}
public abstract void DoWork();
}
public class DbWorker: Worker<DbComponent>
{
public DbWorker(DbComponent component): base(component) {}
public override DoWork() {...}
}
and implement some factory to create specific workers from specific components.
Have you considered having Operator and Component packaged together, and DBComponent in a second project, as for the other projecs of the solution ? Then, you could use a light container such as Spring.net to configure your .exe and load the relevant assemblies.
It is the right thing to give your Component behaviours instead of having the worker class manipulating its properties.
If you don't want other project to see the doWork method, hide it behind an public interface and create an adapter from the public interface to your internal one.
public interface ComponentPublic {
void sharedMethod();
}
public class ComponentPublicAdapter implement ComponentPublic {
private Component component;
void sharedMethod() {
// Do something, may be call doWork()
}
}
Package the ComponentPublic interface in a different project/namespace, therefore other projects may interact with it without knowing the internal interface. Use a dependency injection framework or reflection to instantiate the adapter and Components.
Related
(Using Unity 4.0.1)
Given a UnityContainer object, is there any way to retrieve all the objects that have been instantiated by the container up to that point in time? E.g. something like
IEnumerable<object> instantiatedObjects = unityContainer.GetAllInstantiatedObjects();
or, even better, filtering according to those that derive from a given type:
IEnumerable<IFoo> instantiatedFoos = unityContainer.GetAllInstantiatedObjects<IFoo>();
Following RB's suggestion, the following approach implements a custom Unity extension with a strategy that keeps a reference to each instantiated object upon PostInitializtion.
N.B. The following code is for illustration only, and is not intended to be thread-safe/exception-safe etc.
First, the implementation of the Extension class and other classes it relies on.
public class ObjectContainer
{
private readonly List<object> _instantiatedObjects = new List<object>();
public void Add(object instantiatedObject)
{
_instantiatedObjects.Add(instantiatedObject);
}
public IEnumerable<object> GetInstantiatedObjects()
{
return _instantiatedObjects;
}
public IEnumerable<T> GetInstantiatedObjects<T>()
{
return GetInstantiatedObjects().OfType<T>();
}
}
public class InstantiatedObjectsStrategy : BuilderStrategy
{
private readonly ObjectContainer _objectContainer;
public InstantiatedObjectsStrategy(ObjectContainer objectContainer)
{
_objectContainer = objectContainer;
}
public override void PostBuildUp(IBuilderContext context)
{
_objectContainer.Add(context.Existing);
}
}
public class InstantiatedObjectsExtension : UnityContainerExtension
{
private readonly ObjectContainer _objectContainer = new ObjectContainer();
protected override void Initialize()
{
Context.Container.RegisterInstance(_objectContainer);
Context.Strategies.Add(new InstantiatedObjectsStrategy(_objectContainer),
UnityBuildStage.PostInitialization);
}
}
The extension can be added to the UnityContainer immediately after creation:
IUnityContainer container = new UnityContainer();
container.AddNewExtension<InstantiatedObjectsExtension>();
The instantiated objects can then be retrieved from the container at a later stage as follows:
IEnumerable<object> instantiatedObjects = container.Resolve<ObjectContainer>().GetInstantiatedObjects();
IEnumerable<Foo> instantiatedFoos = container.Resolve<ObjectContainer>().GetInstantiatedObjects<Foo>();
I'm trying to get started with SimpleInjector as an IOC Container and up to now I'm pretty happy with it. But right now I'm stuck on a problem I can't solve. I searched on SO and in the documentation, but it seems to be not answered yet. I've seen the howto doc from SimpleInjector but that doesn't cover open generic interfaces.
I have two generic interfaces like these:
public interface IEventPublisher<TEvent>
{
void Publish(TEvent Event);
}
public interface IEventSubscriber<TEvent>
{
void Subscribe(Action<TEvent> CallBack);
}
And one open generic implementation for those two:
class EventMediator<T> : IEventPublisher<T>, IEventSubscriber<T>
{
List<Action<T>> Subscriptions = new List<Action<T>>();
public void Publish(T Event)
{
foreach (var Subscription in this.Subscriptions)
Subscription.Invoke(Event);
}
public void Subscribe(Action<T> CallBack)
{
this.Subscriptions.Add(CallBack);
}
}
In my Application I'm setting up SimpleInjector like this:
this.Container = new SimpleInjector.Container();
this.Container.RegisterOpenGeneric(typeof(IEventPublisher<>), typeof(EventMediator<>), Lifestyle.Singleton);
this.Container.RegisterOpenGeneric(typeof(IEventSubscriber<>), typeof(EventMediator<>), Lifestyle.Singleton);
this.Container.Verify();
What I'm trying to archive is:
I'd like to get exactly the same instance when asking for a IEventPublisher or an IEventSubscriber. And furthermore this Instance shall be a singleton for any T.
I've tested this with these lines:
class DummyEvent {}
var p = this.Container.GetInstance<IEventPublisher<DummyEvent>>();
var s = this.Container.GetInstance<IEventSubscriber<DummyEvent>>();
var areSame = (object.ReferenceEquals(p,s));
Unfortunatly p and s don't refer to the same instance. Anyone happens to know a solution to this problem?
There are certain solutions for this, here's one: Create separate implementations for IEventPublisher<T> and IEventSubscriber<T> and let them delegate to the EventMediator<T>. For instance with these implementations:
public class EventPublisher<TEvent> : IEventPublisher<TEvent>
{
private readonly EventMediator<TEvent> mediator;
public EventPublisher(EventMediator<TEvent> mediator) {
this.mediator = mediator;
}
public void Publish(TEvent Event) {
this.mediator.Publish(Event);
}
}
public class EventSubscriber<TEvent> : IEventSubscriber<TEvent>
{
private readonly EventMediator<TEvent> mediator;
public EventSubscriber(EventMediator<TEvent> mediator) {
this.mediator = mediator;
}
public void Subscribe(Action<TEvent> CallBack) {
this.mediator.Subscribe(Callback);
}
}
Now you make the registrations as follows:
container.RegisterSingleOpenGeneric(typeof(EventMediator<>), typeof(EventMediator<>));
container.RegisterSingleOpenGeneric(typeof(IEventPublisher<>), typeof(EventPublisher<>));
container.RegisterSingleOpenGeneric(typeof(IEventSubscriber<>), typeof(EventSubscriber<>));
Now both the EventPublisher<DummyEvent> and EventSubscriber<DummyEvent> will point at the same EventMediator<DummyEvent> instance.
Another way to achieve this without the extra type is to make use of the ResolveUnregisteredType event (which is what the RegisterOpenGeneric extension method itself uses under the covers). Your configuration would look like this:
container.RegisterSingleOpenGeneric(typeof(EventMediator<>), typeof(EventMediator<>));
container.ResolveUnregisteredType += (s, e) =>
{
if (e.UnregisteredServiceType.IsGenericType)
{
var def = e.UnregisteredServiceType.GetGenericTypeDefinition();
if (def == typeof(IEventPublisher<>) || def == typeof(IEventSubscriber<>))
{
var mediatorType = typeof(EventMediator<>)
.MakeGenericType(e.UnregisteredServiceType.GetGenericArguments()[0]);
var producer = container.GetRegistration(mediatorType, true);
e.Register(producer.Registration);
}
}
};
You could even extract this code into a more general extension method. This way your registration would look like this:
container.RegisterSingleOpenGeneric(typeof(EventMediator<>), typeof(EventMediator<>));
container.ForwardOpenGenericTo(typeof(IEventPublisher<>), typeof(EventMediator<>));
container.ForwardOpenGenericTo(typeof(IEventSubscriber<>), typeof(EventMediator<>));
The extension method would look like this:
public static void ForwardOpenGenericTo(this Container container,
Type openGenericServiceType, Type openGenericServiceTypeToForwardTo)
{
container.ResolveUnregisteredType += (s, e) =>
{
var type = e.UnregisteredServiceType;
if (type.IsGenericType)
{
if (type.GetGenericTypeDefinition() == openGenericServiceType)
{
var forwardToType = openGenericServiceTypeToForwardTo.MakeGenericType(
type.GetGenericArguments());
var producer = container.GetRegistration(forwardToType, true);
e.Register(producer.Registration);
}
}
};
}
You are registering IEventPublisher and IEventSubscriber as separate singletons. You will need to refactor your code in one way or another. One solution is to separate the 3 responsibilities of your mediator:
The Subscriber
public interface IEventSubscriber<TEvent>
{
void Subscribe(Action<TEvent> CallBack);
}
public class EventSubscriber<T> : IEventSubscriber<T>
{
public readonly ISubscriptions<T> subscriptions;
public EventSubscriber(ISubscriptions<T> subscriptions)
{
this.subscriptions = subscriptions;
}
public void Subscribe(Action<T> CallBack)
{
this.subscriptions.Add(CallBack);
}
}
The Publisher
public interface IEventPublisher<TEvent>
{
void Publish(TEvent Event);
}
public class EventPublisher<T> : IEventPublisher<T>
{
public readonly ISubscriptions<T> subscriptions;
public EventPublisher(ISubscriptions<T> subscriptions)
{
this.subscriptions = subscriptions;
}
public void Publish(T Event)
{
foreach (var subscription in this.subscriptions)
{
subscription.Invoke(Event);
}
}
}
The Subscriptions
public interface ISubscriptions<T> : IList<Action<T>> { }
public class Subscriptions<T> : List<Action<T>>, ISubscriptions<T> { }
Only the subscriptions need to be registered as singleton
var container = new Container();
container.RegisterOpenGeneric(typeof(IEventSubscriber<>), typeof(EventSubscriber<>));
container.RegisterOpenGeneric(typeof(IEventPublisher<>), typeof(EventPublisher<>));
container.RegisterSingleOpenGeneric(typeof(ISubscriptions<>), typeof(Subscriptions<>));
container.Verify();
var p = container.GetInstance<IEventPublisher<DummyEvent>>();
var s = container.GetInstance<IEventSubscriber<DummyEvent>>();
Assert.That(
(p as EventPublisher<DummyEvent>).subscriptions ==
(s as EventSubscriber<DummyEvent>).subscriptions);
In my system I have 16 different classes alike used for statistics. They look like the following
public class myClass : myInheritage
{
private static myClass _instance;
public static myClass Instance
{
get { return _instance ?? (_instance = new myClass(); }
}
public static void Reset()
{
_instance = null;
}
}
They are all made into singletons
myInheritage looks like this:
public class myInheritage
{
int data = 0;
public myInheritage()
{
}
public int Data
{
get { return data; }
set { data+= value; }
}
}
The program is made, so the user chooses which class he wants to make statistics with.
Something like this is what I want
public void statistics(Object myObject, string name)
{
Object x = myObject;
x.Data = 10;
x.Data();
}
Called from another class
statistics(myClass.Instance, "myClass");
statistics(myClass2.Instance, "myClass2)";
So I want to dynamically change my instance in my statistics class.
Is that possible with .NET 2.0 ?
You could use reflection...
MethodInfo method = myObject.GetType().GetMethod("Reset");
if (method != null) method.Invoke(myObject, null);
If you can modify the classes themselves, a better approach might be to have each implement an interface (or base class) IResettable.
public interface IResettable
{
void Reset();
}
public class myClass : myInheritage, IResettable
{
public void Reset() { ... }
}
Then you could write the function against the interface:
public void statistics(IResettable myObject, string name)
{
myObject.Reset();
}
Yes. What you want here is a Strategy/Factory pattern. I name both as they could be used in conjunction for your case. There are great examples of these design patterns here and the following are detailed intros to the Strategy pattern and the Factory pattern. The former of the last two links also shows you how to combine the two to do exactly waht you require.
So in your case, you could set up the following interface
public interface IStatistics
{
// Some method used by all classes to impose statistics.
void ImposeStatistics();
}
Then in you singleton classes you could have
public class myClass : myInheritage, IStatistics
{
private static myClass _instance;
public static myClass Instance
{
get { return _instance ?? (_instance = new myClass()); }
}
public static void Reset()
{
_instance = null;
}
// You would also inherit from IStatistics in your other classes.
public void ImposeStatistics()
{
// Do stuff.
}
}
Then you would have a 'factory' class that imposes you stratgey at runtime.
public static class StatisticFactory
{
public static void ImposeStatistics(IStatistics statsType)
{
statsType.ImposeStatistics();
}
/// <summary>
/// Get the conversion type.
/// </summary>
/// <param name="col">The column to perform the conversion upon.</param>
public static IStatistics GetStatsType(string typeName)
{
switch (typeName)
{
case "BoseEinstein":
return new BoseEinsteinStats();
case "FermiDirac":
return new FermiDiracStats();
default:
return null;
}
}
}
You can then call this like
// Run stats.
IStatistics stats = StatisticFactory(GetStatsType("BoseEinstein"));
to get the statistics for the required class.
I hope this helps.
Problem:
in my domain layer assembly I store two interfaces:
public interface IDomainEvent { }
and
public interface IHandle<T> where T: IDomainEvent, new()
EventDispatcher class is defined there also:
public static class EventDispatcher {
[ThreadStatic]
private static List<Delegate> actions;
[ThreadStatic]
private static List<Object> handlers;
public static List<Object> Handlers {
get { return handlers; }
set { handlers = value; }
}
public static void Register<T>(Action<T> callback) where T : IDomainEvent, new() {
if(null == actions) {
actions = new List<Delegate>();
actions.Add(callback);
}
}
public static void ClearCallbacks() {
actions = null;
}
public static void Raise<T>(T #event) where T : IDomainEvent, new() {
if(null != Handlers) {
foreach(var handler in Handlers.Where(h => h is IHandle<T>)) {
((IHandle<T>)handler).Handle(#event);
}
}
if(null != actions) {
foreach(var action in actions) {
if(action is Action<T>) {
((Action<T>)action)(#event);
}
}
} // if(null != actions) {
}
}
There's a module in presentation layer assembly:
public class EventDispatchingModule : NinjectModule {
public override void Load() {
// EventDispatcher.Handlers = this.Kernel.GetAll(IHandle<T>); Can't do that!
// Bind<IHandle<CarHasBeenRegisteredEvent>>().To<CarHasBeenRegisteredHandler();
}
}
So I can't call Kernel.GetAll(IHandle<T>) there because it can't resolve T parameter.
Howcome I resolve this?
Thanks!
No need to use a module (I've not used ninject, but something similar):
// Put these in the domain project
public class EventDispatcher
{
private static IEventDispatcher _dispatcher;
public static void Setup(IEventDispatcher dispatcher)
{
_dispatcher = dispatcher;
}
public static void Dispatch<T>(T domainEvent) where T : IDomainEvent
{
_dispatcher.Dispatch<T>(domainEvent);
}
}
public interface IEventDispatcher
{
public void Dispatch<T>(T domainEvent) where T : IDomainEvent;
}
// and this one in the project which has Ninject
public class NinjectEventDispatcher : IEventDispatcher
{
private static IKernel _container;
public NinjectEventDispatcher(IKernel container)
{
_container = container;
}
public void Dispatch<T>(T domainEvent) where T : IDomainEvent
{
foreach (var listener in _container.GetAll<IHandle<T>>())
{
listener.Handle(domainEvent);
}
}
}
// And after the container have been configured:
EventDispatcher.Setup(new NinjectEventDispatcher(_container));
But I don't know how ninject handles scoped objects (which may also want to receive the events).
My container has domain events built in, read more in this article: http://www.codeproject.com/Articles/440665/Having-fun-with-Griffin-Container
Update:
I've updated the code sample to make the domain project unaware of Ninject.
You are not using Service Location with this code. The internals of the event dispatcher is. i.e. none of your code is affected by it.
You can get all Handlers with following code
Kernel.GetAll(typeof (IHandle<>));
But anyway it's not good idea to load all IHanders in NInjectModule because you don't know if another modules are already loaded or not (and another modules can register Handlers too).
I suggest make EventDispatcher class not static and register it in scope that you need (If you need new handlers for each request - in request scope, otherwise - in singleton scope . Handlers you can inject with constructor like :
Kerner.Bind<EventDispatcher>().ToSelf()
.InRequestScope()
.WithConstructorArgument("handlers", c => c.Kernel.GetAll(typeof(IHandler<>)))
Hope this helps
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()
{
}
}