How to use DI container to resolve dependencies in Strategy Pattern?
up vote
1
down vote
favorite
I currently working on an application that will act differently based on userInput. So I think about the Strategy Pattern. Below is my implementation:
I have some business logic:
interface IBusinessLogic
{
void DoBusinessLogic();
}
class TypeABusinessLogic : IBusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type A");
}
}
class TypeBBusinessLogic : IBusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type B");
}
}
And, also some application logic:
interface IApplicationLogic
{
void DoApplicationLogic();
}
class TypeAApplicationLogic : IApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type A");
}
}
class TypeBApplicationLogic : IApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type B");
}
}
Now, my strategies need to do both business logic and application logic
interface IStrategy
{
void DoWork();
}
abstract class StrategyBase : IStrategy
{
private IBusinessLogic _businessLogic;
private IApplicationLogic _applicationLogic;
protected StrategyBase(IBusinessLogic businessLogic, IApplicationLogic applicationLogic)
{
_businessLogic = businessLogic;
_applicationLogic = applicationLogic;
}
public void DoWork()
{
_businessLogic.DoBusinessLogic();
_applicationLogic.DoApplicationLogic();
}
}
class TypeAStrategy : IStrategy
{
public TypeAStrategy(TypeABussinessLogic businessLogic, TypeAApplicationLogic applicationLogic) : base(businessLogic, applicationLogic)
{}
}
class TypeBStrategy : IStrategy
{
public TypeBStrategy(TypeBBussinessLogic businessLogic, TypeBApplicationLogic applicationLogic) : base(businessLogic, applicationLogic)
{}
}
Now is my Context class
class Context
{
private Func<string, IStrategy> _strategyFactory;
public Context(Func<string, IStrategy> strategyFactory)
{
_strategyFactory = strategyFactory;
}
public void Run()
{
string userInput = GetUserInput(); //"TypeA" or "TypeB"
IStrategy strategy = _strategyFactory(userInput);
strategy.DoWork();
}
}
Here is my DI builder code:
var builder = new ContainerBuilder();
builder.RegisterType<TypeAStrategy>().As<IStrategy>().Keyed<IStrategy>("TypeA");
var builder = new ContainerBuilder();
builder.RegisterType<TypeBStrategy>().As<IStrategy>().Keyed<IStrategy>("TypeB");
builder.Register<Func<string, IStrategy>>( c =>
{
var componentContext = c.Resolve<IComponentContext>();
return (key) =>
{
IStrategy stategy = componentContext.ResolveKeyed<IStrategy >(key);
return stategy;
};
});
The problem I can see here is my strategies (TypeAStrategy, TypeBStrategy) depend directly on concrete class (TypeABusinessLogic,TypeAApplicationLogic,TypeBBusinessLogic, TypeBApplicationLogic), which is not good. I can't mock these dependencies in unit test.
If I let my strategies depend on interfaces, I dont know how to implement DI container to resolve dependencies (Notes: I currently using Autofac, but I can use any other DI containers )
Please advise.
c# design-patterns dependency-injection autofac ioc-container
|
show 3 more comments
up vote
1
down vote
favorite
I currently working on an application that will act differently based on userInput. So I think about the Strategy Pattern. Below is my implementation:
I have some business logic:
interface IBusinessLogic
{
void DoBusinessLogic();
}
class TypeABusinessLogic : IBusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type A");
}
}
class TypeBBusinessLogic : IBusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type B");
}
}
And, also some application logic:
interface IApplicationLogic
{
void DoApplicationLogic();
}
class TypeAApplicationLogic : IApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type A");
}
}
class TypeBApplicationLogic : IApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type B");
}
}
Now, my strategies need to do both business logic and application logic
interface IStrategy
{
void DoWork();
}
abstract class StrategyBase : IStrategy
{
private IBusinessLogic _businessLogic;
private IApplicationLogic _applicationLogic;
protected StrategyBase(IBusinessLogic businessLogic, IApplicationLogic applicationLogic)
{
_businessLogic = businessLogic;
_applicationLogic = applicationLogic;
}
public void DoWork()
{
_businessLogic.DoBusinessLogic();
_applicationLogic.DoApplicationLogic();
}
}
class TypeAStrategy : IStrategy
{
public TypeAStrategy(TypeABussinessLogic businessLogic, TypeAApplicationLogic applicationLogic) : base(businessLogic, applicationLogic)
{}
}
class TypeBStrategy : IStrategy
{
public TypeBStrategy(TypeBBussinessLogic businessLogic, TypeBApplicationLogic applicationLogic) : base(businessLogic, applicationLogic)
{}
}
Now is my Context class
class Context
{
private Func<string, IStrategy> _strategyFactory;
public Context(Func<string, IStrategy> strategyFactory)
{
_strategyFactory = strategyFactory;
}
public void Run()
{
string userInput = GetUserInput(); //"TypeA" or "TypeB"
IStrategy strategy = _strategyFactory(userInput);
strategy.DoWork();
}
}
Here is my DI builder code:
var builder = new ContainerBuilder();
builder.RegisterType<TypeAStrategy>().As<IStrategy>().Keyed<IStrategy>("TypeA");
var builder = new ContainerBuilder();
builder.RegisterType<TypeBStrategy>().As<IStrategy>().Keyed<IStrategy>("TypeB");
builder.Register<Func<string, IStrategy>>( c =>
{
var componentContext = c.Resolve<IComponentContext>();
return (key) =>
{
IStrategy stategy = componentContext.ResolveKeyed<IStrategy >(key);
return stategy;
};
});
The problem I can see here is my strategies (TypeAStrategy, TypeBStrategy) depend directly on concrete class (TypeABusinessLogic,TypeAApplicationLogic,TypeBBusinessLogic, TypeBApplicationLogic), which is not good. I can't mock these dependencies in unit test.
If I let my strategies depend on interfaces, I dont know how to implement DI container to resolve dependencies (Notes: I currently using Autofac, but I can use any other DI containers )
Please advise.
c# design-patterns dependency-injection autofac ioc-container
1
You don't use the DI container to resolve dynamic input from the user (Any injection should be complete after bootstrapping). You could use factories. DI could be used to inject the available factories, along with the names to use for those factories. For example, using Unity you could pull the factory registrations out into a config file. You could then modify the factories that are registered from the config file without recompiling your program, and give each factory a unique name. You could supply any name you wanted for each individual factory, doesn't need to be the class name.
– Ryan Pierce Williams
Nov 8 at 21:48
@Ryan: Can you provide more details on how to register dependencies for my strategy. Any example code (even in Unity) is really appreciated. I add my ContainerBuilder code to make it more clear.
– TrBaPhong
Nov 8 at 22:05
If someone else doesn't do it before I can, I'll put together an example tonight. At any rate, your current hierarchy doesn't require intermediate interfaces for each strategy. Your strategies aren't adding anything new in terms of functionality or in terms of properties, so your base IStrategy interface is all you need for mocking purposes.
– Ryan Pierce Williams
Nov 8 at 22:23
What do you mean "intermediate interfaces for each strategy"? Are you talking about IBusinessLogic, IApplicationLogic? I think it necessary because I wanna separate different logic categories into different classes (TypeABusinessLogic and TypeAApplicationLogic handle different logic). It helps my achieve Single Reponsibility.
– TrBaPhong
Nov 9 at 3:13
I mean that you don't need an ITypeAStrategy or ITypeBStrategy interface. The strategies don't add any functionality/properties so you can mock them both just using the base IStrategy interface.
– Ryan Pierce Williams
Nov 9 at 5:07
|
show 3 more comments
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I currently working on an application that will act differently based on userInput. So I think about the Strategy Pattern. Below is my implementation:
I have some business logic:
interface IBusinessLogic
{
void DoBusinessLogic();
}
class TypeABusinessLogic : IBusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type A");
}
}
class TypeBBusinessLogic : IBusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type B");
}
}
And, also some application logic:
interface IApplicationLogic
{
void DoApplicationLogic();
}
class TypeAApplicationLogic : IApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type A");
}
}
class TypeBApplicationLogic : IApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type B");
}
}
Now, my strategies need to do both business logic and application logic
interface IStrategy
{
void DoWork();
}
abstract class StrategyBase : IStrategy
{
private IBusinessLogic _businessLogic;
private IApplicationLogic _applicationLogic;
protected StrategyBase(IBusinessLogic businessLogic, IApplicationLogic applicationLogic)
{
_businessLogic = businessLogic;
_applicationLogic = applicationLogic;
}
public void DoWork()
{
_businessLogic.DoBusinessLogic();
_applicationLogic.DoApplicationLogic();
}
}
class TypeAStrategy : IStrategy
{
public TypeAStrategy(TypeABussinessLogic businessLogic, TypeAApplicationLogic applicationLogic) : base(businessLogic, applicationLogic)
{}
}
class TypeBStrategy : IStrategy
{
public TypeBStrategy(TypeBBussinessLogic businessLogic, TypeBApplicationLogic applicationLogic) : base(businessLogic, applicationLogic)
{}
}
Now is my Context class
class Context
{
private Func<string, IStrategy> _strategyFactory;
public Context(Func<string, IStrategy> strategyFactory)
{
_strategyFactory = strategyFactory;
}
public void Run()
{
string userInput = GetUserInput(); //"TypeA" or "TypeB"
IStrategy strategy = _strategyFactory(userInput);
strategy.DoWork();
}
}
Here is my DI builder code:
var builder = new ContainerBuilder();
builder.RegisterType<TypeAStrategy>().As<IStrategy>().Keyed<IStrategy>("TypeA");
var builder = new ContainerBuilder();
builder.RegisterType<TypeBStrategy>().As<IStrategy>().Keyed<IStrategy>("TypeB");
builder.Register<Func<string, IStrategy>>( c =>
{
var componentContext = c.Resolve<IComponentContext>();
return (key) =>
{
IStrategy stategy = componentContext.ResolveKeyed<IStrategy >(key);
return stategy;
};
});
The problem I can see here is my strategies (TypeAStrategy, TypeBStrategy) depend directly on concrete class (TypeABusinessLogic,TypeAApplicationLogic,TypeBBusinessLogic, TypeBApplicationLogic), which is not good. I can't mock these dependencies in unit test.
If I let my strategies depend on interfaces, I dont know how to implement DI container to resolve dependencies (Notes: I currently using Autofac, but I can use any other DI containers )
Please advise.
c# design-patterns dependency-injection autofac ioc-container
I currently working on an application that will act differently based on userInput. So I think about the Strategy Pattern. Below is my implementation:
I have some business logic:
interface IBusinessLogic
{
void DoBusinessLogic();
}
class TypeABusinessLogic : IBusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type A");
}
}
class TypeBBusinessLogic : IBusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type B");
}
}
And, also some application logic:
interface IApplicationLogic
{
void DoApplicationLogic();
}
class TypeAApplicationLogic : IApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type A");
}
}
class TypeBApplicationLogic : IApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type B");
}
}
Now, my strategies need to do both business logic and application logic
interface IStrategy
{
void DoWork();
}
abstract class StrategyBase : IStrategy
{
private IBusinessLogic _businessLogic;
private IApplicationLogic _applicationLogic;
protected StrategyBase(IBusinessLogic businessLogic, IApplicationLogic applicationLogic)
{
_businessLogic = businessLogic;
_applicationLogic = applicationLogic;
}
public void DoWork()
{
_businessLogic.DoBusinessLogic();
_applicationLogic.DoApplicationLogic();
}
}
class TypeAStrategy : IStrategy
{
public TypeAStrategy(TypeABussinessLogic businessLogic, TypeAApplicationLogic applicationLogic) : base(businessLogic, applicationLogic)
{}
}
class TypeBStrategy : IStrategy
{
public TypeBStrategy(TypeBBussinessLogic businessLogic, TypeBApplicationLogic applicationLogic) : base(businessLogic, applicationLogic)
{}
}
Now is my Context class
class Context
{
private Func<string, IStrategy> _strategyFactory;
public Context(Func<string, IStrategy> strategyFactory)
{
_strategyFactory = strategyFactory;
}
public void Run()
{
string userInput = GetUserInput(); //"TypeA" or "TypeB"
IStrategy strategy = _strategyFactory(userInput);
strategy.DoWork();
}
}
Here is my DI builder code:
var builder = new ContainerBuilder();
builder.RegisterType<TypeAStrategy>().As<IStrategy>().Keyed<IStrategy>("TypeA");
var builder = new ContainerBuilder();
builder.RegisterType<TypeBStrategy>().As<IStrategy>().Keyed<IStrategy>("TypeB");
builder.Register<Func<string, IStrategy>>( c =>
{
var componentContext = c.Resolve<IComponentContext>();
return (key) =>
{
IStrategy stategy = componentContext.ResolveKeyed<IStrategy >(key);
return stategy;
};
});
The problem I can see here is my strategies (TypeAStrategy, TypeBStrategy) depend directly on concrete class (TypeABusinessLogic,TypeAApplicationLogic,TypeBBusinessLogic, TypeBApplicationLogic), which is not good. I can't mock these dependencies in unit test.
If I let my strategies depend on interfaces, I dont know how to implement DI container to resolve dependencies (Notes: I currently using Autofac, but I can use any other DI containers )
Please advise.
c# design-patterns dependency-injection autofac ioc-container
c# design-patterns dependency-injection autofac ioc-container
edited Nov 9 at 9:01
Steven
125k17211325
125k17211325
asked Nov 8 at 21:41
TrBaPhong
215
215
1
You don't use the DI container to resolve dynamic input from the user (Any injection should be complete after bootstrapping). You could use factories. DI could be used to inject the available factories, along with the names to use for those factories. For example, using Unity you could pull the factory registrations out into a config file. You could then modify the factories that are registered from the config file without recompiling your program, and give each factory a unique name. You could supply any name you wanted for each individual factory, doesn't need to be the class name.
– Ryan Pierce Williams
Nov 8 at 21:48
@Ryan: Can you provide more details on how to register dependencies for my strategy. Any example code (even in Unity) is really appreciated. I add my ContainerBuilder code to make it more clear.
– TrBaPhong
Nov 8 at 22:05
If someone else doesn't do it before I can, I'll put together an example tonight. At any rate, your current hierarchy doesn't require intermediate interfaces for each strategy. Your strategies aren't adding anything new in terms of functionality or in terms of properties, so your base IStrategy interface is all you need for mocking purposes.
– Ryan Pierce Williams
Nov 8 at 22:23
What do you mean "intermediate interfaces for each strategy"? Are you talking about IBusinessLogic, IApplicationLogic? I think it necessary because I wanna separate different logic categories into different classes (TypeABusinessLogic and TypeAApplicationLogic handle different logic). It helps my achieve Single Reponsibility.
– TrBaPhong
Nov 9 at 3:13
I mean that you don't need an ITypeAStrategy or ITypeBStrategy interface. The strategies don't add any functionality/properties so you can mock them both just using the base IStrategy interface.
– Ryan Pierce Williams
Nov 9 at 5:07
|
show 3 more comments
1
You don't use the DI container to resolve dynamic input from the user (Any injection should be complete after bootstrapping). You could use factories. DI could be used to inject the available factories, along with the names to use for those factories. For example, using Unity you could pull the factory registrations out into a config file. You could then modify the factories that are registered from the config file without recompiling your program, and give each factory a unique name. You could supply any name you wanted for each individual factory, doesn't need to be the class name.
– Ryan Pierce Williams
Nov 8 at 21:48
@Ryan: Can you provide more details on how to register dependencies for my strategy. Any example code (even in Unity) is really appreciated. I add my ContainerBuilder code to make it more clear.
– TrBaPhong
Nov 8 at 22:05
If someone else doesn't do it before I can, I'll put together an example tonight. At any rate, your current hierarchy doesn't require intermediate interfaces for each strategy. Your strategies aren't adding anything new in terms of functionality or in terms of properties, so your base IStrategy interface is all you need for mocking purposes.
– Ryan Pierce Williams
Nov 8 at 22:23
What do you mean "intermediate interfaces for each strategy"? Are you talking about IBusinessLogic, IApplicationLogic? I think it necessary because I wanna separate different logic categories into different classes (TypeABusinessLogic and TypeAApplicationLogic handle different logic). It helps my achieve Single Reponsibility.
– TrBaPhong
Nov 9 at 3:13
I mean that you don't need an ITypeAStrategy or ITypeBStrategy interface. The strategies don't add any functionality/properties so you can mock them both just using the base IStrategy interface.
– Ryan Pierce Williams
Nov 9 at 5:07
1
1
You don't use the DI container to resolve dynamic input from the user (Any injection should be complete after bootstrapping). You could use factories. DI could be used to inject the available factories, along with the names to use for those factories. For example, using Unity you could pull the factory registrations out into a config file. You could then modify the factories that are registered from the config file without recompiling your program, and give each factory a unique name. You could supply any name you wanted for each individual factory, doesn't need to be the class name.
– Ryan Pierce Williams
Nov 8 at 21:48
You don't use the DI container to resolve dynamic input from the user (Any injection should be complete after bootstrapping). You could use factories. DI could be used to inject the available factories, along with the names to use for those factories. For example, using Unity you could pull the factory registrations out into a config file. You could then modify the factories that are registered from the config file without recompiling your program, and give each factory a unique name. You could supply any name you wanted for each individual factory, doesn't need to be the class name.
– Ryan Pierce Williams
Nov 8 at 21:48
@Ryan: Can you provide more details on how to register dependencies for my strategy. Any example code (even in Unity) is really appreciated. I add my ContainerBuilder code to make it more clear.
– TrBaPhong
Nov 8 at 22:05
@Ryan: Can you provide more details on how to register dependencies for my strategy. Any example code (even in Unity) is really appreciated. I add my ContainerBuilder code to make it more clear.
– TrBaPhong
Nov 8 at 22:05
If someone else doesn't do it before I can, I'll put together an example tonight. At any rate, your current hierarchy doesn't require intermediate interfaces for each strategy. Your strategies aren't adding anything new in terms of functionality or in terms of properties, so your base IStrategy interface is all you need for mocking purposes.
– Ryan Pierce Williams
Nov 8 at 22:23
If someone else doesn't do it before I can, I'll put together an example tonight. At any rate, your current hierarchy doesn't require intermediate interfaces for each strategy. Your strategies aren't adding anything new in terms of functionality or in terms of properties, so your base IStrategy interface is all you need for mocking purposes.
– Ryan Pierce Williams
Nov 8 at 22:23
What do you mean "intermediate interfaces for each strategy"? Are you talking about IBusinessLogic, IApplicationLogic? I think it necessary because I wanna separate different logic categories into different classes (TypeABusinessLogic and TypeAApplicationLogic handle different logic). It helps my achieve Single Reponsibility.
– TrBaPhong
Nov 9 at 3:13
What do you mean "intermediate interfaces for each strategy"? Are you talking about IBusinessLogic, IApplicationLogic? I think it necessary because I wanna separate different logic categories into different classes (TypeABusinessLogic and TypeAApplicationLogic handle different logic). It helps my achieve Single Reponsibility.
– TrBaPhong
Nov 9 at 3:13
I mean that you don't need an ITypeAStrategy or ITypeBStrategy interface. The strategies don't add any functionality/properties so you can mock them both just using the base IStrategy interface.
– Ryan Pierce Williams
Nov 9 at 5:07
I mean that you don't need an ITypeAStrategy or ITypeBStrategy interface. The strategies don't add any functionality/properties so you can mock them both just using the base IStrategy interface.
– Ryan Pierce Williams
Nov 9 at 5:07
|
show 3 more comments
1 Answer
1
active
oldest
votes
up vote
1
down vote
accepted
So I thought of a few ways to approach this, but I think the cleanest way is to just introduce some token interfaces. A token interface is one which doesn't add any properties or functionality. For instance:
interface IBusinessLogic
{
void DoBusinessLogic();
}
interface ITypeABusinessLogic : IBusinessLogic { }
interface ITypeBBusinessLogic : IBusinessLogic { }
interface IApplicationLogic
{
void DoApplicationLogic();
}
interface ITypeAApplicationLogic : IApplicationLogic { }
interface ITypeBApplicationLogic : IApplicationLogic { }
Next we adjust the classes to implement the relevant token interface:
class TypeABusinessLogic : ITypeABusinessLogic
{
public virtual void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type A");
}
}
class TypeBBusinessLogic : ITypeBBusinessLogic
{
public virtual void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type B");
}
}
class TypeAApplicationLogic : ITypeAApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type A");
}
}
class TypeBApplicationLogic : ITypeBApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type B");
}
}
We can similarly create mock classes by implementing the relevant token interface:
class MockTypeABusinessLogic : ITypeABusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("[Mock] Do Business Logic for Type A");
}
}
class MockTypeBBusinessLogic : ITypeBBusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("[Mock] Do Business Logic for Type B");
}
}
class MockTypeAApplicationLogic : ITypeAApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("[Mock] Do Application Logic for Type A");
}
}
class MockTypeBApplicationLogic : ITypeBApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("[Mock] Do Application Logic for Type B");
}
}
I also modified the IStrategy interface to make injection with Unity a little easier, giving each strategy a Name property (you don't need to do this):
interface IStrategy
{
string Name { get; }
void DoWork();
}
abstract class StrategyBase : IStrategy
{
private IBusinessLogic _businessLogic;
private IApplicationLogic _applicationLogic;
public string Name { get; private set; }
protected StrategyBase(String name, IBusinessLogic businessLogic, IApplicationLogic applicationLogic)
{
this.Name = name;
_businessLogic = businessLogic;
_applicationLogic = applicationLogic;
}
public void DoWork()
{
_businessLogic.DoBusinessLogic();
_applicationLogic.DoApplicationLogic();
}
}
class TypeAStrategy : StrategyBase
{
public TypeAStrategy(String name, ITypeABusinessLogic businessLogic, ITypeAApplicationLogic applicationLogic) : base(name, businessLogic, applicationLogic)
{ }
}
class TypeBStrategy : StrategyBase
{
public TypeBStrategy(String name, ITypeBBusinessLogic businessLogic, ITypeBApplicationLogic applicationLogic) : base(name, businessLogic, applicationLogic)
{ }
}
Using Unity I wrote the following program to test the registrations:
class Context
{
private Dictionary<string, IStrategy> _strategyFactory = new Dictionary<string, IStrategy>();
public Context(IStrategy strategies)
{
foreach (var s in strategies)
{
_strategyFactory.Add(s.Name, s);
}
}
public void Run()
{
string userInput = "TypeA";
IStrategy strategy = _strategyFactory[userInput];
strategy.DoWork();
userInput = "TypeB";
strategy = _strategyFactory[userInput];
strategy.DoWork();
}
}
class Program
{
static void Main(string args)
{
Console.WriteLine("Mock DI Example: ");
UnityContainer ioc = new UnityContainer();
ioc.RegisterType<ITypeABusinessLogic, MockTypeABusinessLogic>();
ioc.RegisterType<ITypeAApplicationLogic, MockTypeAApplicationLogic>();
ioc.RegisterType<ITypeBBusinessLogic, MockTypeBBusinessLogic>();
ioc.RegisterType<ITypeBApplicationLogic, MockTypeBApplicationLogic>();
ioc.RegisterType<IStrategy, TypeAStrategy>("TypeA", new InjectionConstructor("TypeA", typeof(ITypeABusinessLogic), typeof(ITypeAApplicationLogic)));
ioc.RegisterType<IStrategy, TypeBStrategy>("TypeB", new InjectionConstructor("TypeB", typeof(ITypeBBusinessLogic), typeof(ITypeBApplicationLogic)));
Context c = ioc.Resolve<Context>();
c.Run();
Console.WriteLine("nUnmocked DI Example: ");
ioc = new UnityContainer();
ioc.RegisterType<ITypeABusinessLogic, TypeABusinessLogic>();
ioc.RegisterType<ITypeAApplicationLogic, TypeAApplicationLogic>();
ioc.RegisterType<ITypeBBusinessLogic, TypeBBusinessLogic>();
ioc.RegisterType<ITypeBApplicationLogic, TypeBApplicationLogic>();
ioc.RegisterType<IStrategy, TypeAStrategy>("TypeA", new InjectionConstructor("TypeA", typeof(ITypeABusinessLogic), typeof(ITypeAApplicationLogic)));
ioc.RegisterType<IStrategy, TypeBStrategy>("TypeB", new InjectionConstructor("TypeB", typeof(ITypeBBusinessLogic), typeof(ITypeBApplicationLogic)));
c = ioc.Resolve<Context>();
c.Run();
Console.WriteLine("nPress enter to exit...");
Console.ReadLine();
}
And here was my output:
Mock DI Example:
[Mock] Do Business Logic for Type A
[Mock] Do Application Logic for Type A
[Mock] Do Business Logic for Type B
[Mock] Do Application Logic for Type B
Unmocked DI Example:
Do Business Logic for Type A
Do Application Logic for Type A
Do Business Logic for Type B
Do Application Logic for Type B
Press enter to exit...
This isn't the only way to solve the problem, but I think this most directly matches how you have structured your code in the OP. Hope this helps :)
EDIT: Here is one alternative to the above which I think you should consider. It will cut down on your object and interface hierarchy quite a bit. NOTE: you'll need to make the StrategyBase class not abstract, and expose the constructor as public.
Console.WriteLine("nAlternative DI Example: ");
ioc = new UnityContainer();
ioc.RegisterType<IBusinessLogic, TypeABusinessLogic>("TypeA");
ioc.RegisterType<IApplicationLogic, TypeAApplicationLogic>("TypeA");
ioc.RegisterType<IStrategy, StrategyBase>("TypeA", new InjectionConstructor("TypeA", new ResolvedParameter<IBusinessLogic>("TypeA"), new ResolvedParameter<IApplicationLogic>("TypeA") ));
ioc.RegisterType<IBusinessLogic, TypeBBusinessLogic>("TypeB");
ioc.RegisterType<IApplicationLogic, TypeBApplicationLogic>("TypeB");
ioc.RegisterType<IStrategy, StrategyBase>("TypeB", new InjectionConstructor("TypeB", new ResolvedParameter<IBusinessLogic>("TypeB"), new ResolvedParameter<IApplicationLogic>("TypeB")));
c = ioc.Resolve<Context>();
c.Run();
Since your classes and the token interfaces don't actually provide you any functionality, they only serve as a means of differentiating the specific implementations. But DI containers already have a simple means of doing this: strings. In Unity you can use the same string for different types, like above. You can use this to delineate which specific implementations go together. This is my recommendation :)
1
Thanks Ryan for your help. The token interface idea help me solved the problem
– TrBaPhong
Nov 9 at 19:40
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
So I thought of a few ways to approach this, but I think the cleanest way is to just introduce some token interfaces. A token interface is one which doesn't add any properties or functionality. For instance:
interface IBusinessLogic
{
void DoBusinessLogic();
}
interface ITypeABusinessLogic : IBusinessLogic { }
interface ITypeBBusinessLogic : IBusinessLogic { }
interface IApplicationLogic
{
void DoApplicationLogic();
}
interface ITypeAApplicationLogic : IApplicationLogic { }
interface ITypeBApplicationLogic : IApplicationLogic { }
Next we adjust the classes to implement the relevant token interface:
class TypeABusinessLogic : ITypeABusinessLogic
{
public virtual void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type A");
}
}
class TypeBBusinessLogic : ITypeBBusinessLogic
{
public virtual void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type B");
}
}
class TypeAApplicationLogic : ITypeAApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type A");
}
}
class TypeBApplicationLogic : ITypeBApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type B");
}
}
We can similarly create mock classes by implementing the relevant token interface:
class MockTypeABusinessLogic : ITypeABusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("[Mock] Do Business Logic for Type A");
}
}
class MockTypeBBusinessLogic : ITypeBBusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("[Mock] Do Business Logic for Type B");
}
}
class MockTypeAApplicationLogic : ITypeAApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("[Mock] Do Application Logic for Type A");
}
}
class MockTypeBApplicationLogic : ITypeBApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("[Mock] Do Application Logic for Type B");
}
}
I also modified the IStrategy interface to make injection with Unity a little easier, giving each strategy a Name property (you don't need to do this):
interface IStrategy
{
string Name { get; }
void DoWork();
}
abstract class StrategyBase : IStrategy
{
private IBusinessLogic _businessLogic;
private IApplicationLogic _applicationLogic;
public string Name { get; private set; }
protected StrategyBase(String name, IBusinessLogic businessLogic, IApplicationLogic applicationLogic)
{
this.Name = name;
_businessLogic = businessLogic;
_applicationLogic = applicationLogic;
}
public void DoWork()
{
_businessLogic.DoBusinessLogic();
_applicationLogic.DoApplicationLogic();
}
}
class TypeAStrategy : StrategyBase
{
public TypeAStrategy(String name, ITypeABusinessLogic businessLogic, ITypeAApplicationLogic applicationLogic) : base(name, businessLogic, applicationLogic)
{ }
}
class TypeBStrategy : StrategyBase
{
public TypeBStrategy(String name, ITypeBBusinessLogic businessLogic, ITypeBApplicationLogic applicationLogic) : base(name, businessLogic, applicationLogic)
{ }
}
Using Unity I wrote the following program to test the registrations:
class Context
{
private Dictionary<string, IStrategy> _strategyFactory = new Dictionary<string, IStrategy>();
public Context(IStrategy strategies)
{
foreach (var s in strategies)
{
_strategyFactory.Add(s.Name, s);
}
}
public void Run()
{
string userInput = "TypeA";
IStrategy strategy = _strategyFactory[userInput];
strategy.DoWork();
userInput = "TypeB";
strategy = _strategyFactory[userInput];
strategy.DoWork();
}
}
class Program
{
static void Main(string args)
{
Console.WriteLine("Mock DI Example: ");
UnityContainer ioc = new UnityContainer();
ioc.RegisterType<ITypeABusinessLogic, MockTypeABusinessLogic>();
ioc.RegisterType<ITypeAApplicationLogic, MockTypeAApplicationLogic>();
ioc.RegisterType<ITypeBBusinessLogic, MockTypeBBusinessLogic>();
ioc.RegisterType<ITypeBApplicationLogic, MockTypeBApplicationLogic>();
ioc.RegisterType<IStrategy, TypeAStrategy>("TypeA", new InjectionConstructor("TypeA", typeof(ITypeABusinessLogic), typeof(ITypeAApplicationLogic)));
ioc.RegisterType<IStrategy, TypeBStrategy>("TypeB", new InjectionConstructor("TypeB", typeof(ITypeBBusinessLogic), typeof(ITypeBApplicationLogic)));
Context c = ioc.Resolve<Context>();
c.Run();
Console.WriteLine("nUnmocked DI Example: ");
ioc = new UnityContainer();
ioc.RegisterType<ITypeABusinessLogic, TypeABusinessLogic>();
ioc.RegisterType<ITypeAApplicationLogic, TypeAApplicationLogic>();
ioc.RegisterType<ITypeBBusinessLogic, TypeBBusinessLogic>();
ioc.RegisterType<ITypeBApplicationLogic, TypeBApplicationLogic>();
ioc.RegisterType<IStrategy, TypeAStrategy>("TypeA", new InjectionConstructor("TypeA", typeof(ITypeABusinessLogic), typeof(ITypeAApplicationLogic)));
ioc.RegisterType<IStrategy, TypeBStrategy>("TypeB", new InjectionConstructor("TypeB", typeof(ITypeBBusinessLogic), typeof(ITypeBApplicationLogic)));
c = ioc.Resolve<Context>();
c.Run();
Console.WriteLine("nPress enter to exit...");
Console.ReadLine();
}
And here was my output:
Mock DI Example:
[Mock] Do Business Logic for Type A
[Mock] Do Application Logic for Type A
[Mock] Do Business Logic for Type B
[Mock] Do Application Logic for Type B
Unmocked DI Example:
Do Business Logic for Type A
Do Application Logic for Type A
Do Business Logic for Type B
Do Application Logic for Type B
Press enter to exit...
This isn't the only way to solve the problem, but I think this most directly matches how you have structured your code in the OP. Hope this helps :)
EDIT: Here is one alternative to the above which I think you should consider. It will cut down on your object and interface hierarchy quite a bit. NOTE: you'll need to make the StrategyBase class not abstract, and expose the constructor as public.
Console.WriteLine("nAlternative DI Example: ");
ioc = new UnityContainer();
ioc.RegisterType<IBusinessLogic, TypeABusinessLogic>("TypeA");
ioc.RegisterType<IApplicationLogic, TypeAApplicationLogic>("TypeA");
ioc.RegisterType<IStrategy, StrategyBase>("TypeA", new InjectionConstructor("TypeA", new ResolvedParameter<IBusinessLogic>("TypeA"), new ResolvedParameter<IApplicationLogic>("TypeA") ));
ioc.RegisterType<IBusinessLogic, TypeBBusinessLogic>("TypeB");
ioc.RegisterType<IApplicationLogic, TypeBApplicationLogic>("TypeB");
ioc.RegisterType<IStrategy, StrategyBase>("TypeB", new InjectionConstructor("TypeB", new ResolvedParameter<IBusinessLogic>("TypeB"), new ResolvedParameter<IApplicationLogic>("TypeB")));
c = ioc.Resolve<Context>();
c.Run();
Since your classes and the token interfaces don't actually provide you any functionality, they only serve as a means of differentiating the specific implementations. But DI containers already have a simple means of doing this: strings. In Unity you can use the same string for different types, like above. You can use this to delineate which specific implementations go together. This is my recommendation :)
1
Thanks Ryan for your help. The token interface idea help me solved the problem
– TrBaPhong
Nov 9 at 19:40
add a comment |
up vote
1
down vote
accepted
So I thought of a few ways to approach this, but I think the cleanest way is to just introduce some token interfaces. A token interface is one which doesn't add any properties or functionality. For instance:
interface IBusinessLogic
{
void DoBusinessLogic();
}
interface ITypeABusinessLogic : IBusinessLogic { }
interface ITypeBBusinessLogic : IBusinessLogic { }
interface IApplicationLogic
{
void DoApplicationLogic();
}
interface ITypeAApplicationLogic : IApplicationLogic { }
interface ITypeBApplicationLogic : IApplicationLogic { }
Next we adjust the classes to implement the relevant token interface:
class TypeABusinessLogic : ITypeABusinessLogic
{
public virtual void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type A");
}
}
class TypeBBusinessLogic : ITypeBBusinessLogic
{
public virtual void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type B");
}
}
class TypeAApplicationLogic : ITypeAApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type A");
}
}
class TypeBApplicationLogic : ITypeBApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type B");
}
}
We can similarly create mock classes by implementing the relevant token interface:
class MockTypeABusinessLogic : ITypeABusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("[Mock] Do Business Logic for Type A");
}
}
class MockTypeBBusinessLogic : ITypeBBusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("[Mock] Do Business Logic for Type B");
}
}
class MockTypeAApplicationLogic : ITypeAApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("[Mock] Do Application Logic for Type A");
}
}
class MockTypeBApplicationLogic : ITypeBApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("[Mock] Do Application Logic for Type B");
}
}
I also modified the IStrategy interface to make injection with Unity a little easier, giving each strategy a Name property (you don't need to do this):
interface IStrategy
{
string Name { get; }
void DoWork();
}
abstract class StrategyBase : IStrategy
{
private IBusinessLogic _businessLogic;
private IApplicationLogic _applicationLogic;
public string Name { get; private set; }
protected StrategyBase(String name, IBusinessLogic businessLogic, IApplicationLogic applicationLogic)
{
this.Name = name;
_businessLogic = businessLogic;
_applicationLogic = applicationLogic;
}
public void DoWork()
{
_businessLogic.DoBusinessLogic();
_applicationLogic.DoApplicationLogic();
}
}
class TypeAStrategy : StrategyBase
{
public TypeAStrategy(String name, ITypeABusinessLogic businessLogic, ITypeAApplicationLogic applicationLogic) : base(name, businessLogic, applicationLogic)
{ }
}
class TypeBStrategy : StrategyBase
{
public TypeBStrategy(String name, ITypeBBusinessLogic businessLogic, ITypeBApplicationLogic applicationLogic) : base(name, businessLogic, applicationLogic)
{ }
}
Using Unity I wrote the following program to test the registrations:
class Context
{
private Dictionary<string, IStrategy> _strategyFactory = new Dictionary<string, IStrategy>();
public Context(IStrategy strategies)
{
foreach (var s in strategies)
{
_strategyFactory.Add(s.Name, s);
}
}
public void Run()
{
string userInput = "TypeA";
IStrategy strategy = _strategyFactory[userInput];
strategy.DoWork();
userInput = "TypeB";
strategy = _strategyFactory[userInput];
strategy.DoWork();
}
}
class Program
{
static void Main(string args)
{
Console.WriteLine("Mock DI Example: ");
UnityContainer ioc = new UnityContainer();
ioc.RegisterType<ITypeABusinessLogic, MockTypeABusinessLogic>();
ioc.RegisterType<ITypeAApplicationLogic, MockTypeAApplicationLogic>();
ioc.RegisterType<ITypeBBusinessLogic, MockTypeBBusinessLogic>();
ioc.RegisterType<ITypeBApplicationLogic, MockTypeBApplicationLogic>();
ioc.RegisterType<IStrategy, TypeAStrategy>("TypeA", new InjectionConstructor("TypeA", typeof(ITypeABusinessLogic), typeof(ITypeAApplicationLogic)));
ioc.RegisterType<IStrategy, TypeBStrategy>("TypeB", new InjectionConstructor("TypeB", typeof(ITypeBBusinessLogic), typeof(ITypeBApplicationLogic)));
Context c = ioc.Resolve<Context>();
c.Run();
Console.WriteLine("nUnmocked DI Example: ");
ioc = new UnityContainer();
ioc.RegisterType<ITypeABusinessLogic, TypeABusinessLogic>();
ioc.RegisterType<ITypeAApplicationLogic, TypeAApplicationLogic>();
ioc.RegisterType<ITypeBBusinessLogic, TypeBBusinessLogic>();
ioc.RegisterType<ITypeBApplicationLogic, TypeBApplicationLogic>();
ioc.RegisterType<IStrategy, TypeAStrategy>("TypeA", new InjectionConstructor("TypeA", typeof(ITypeABusinessLogic), typeof(ITypeAApplicationLogic)));
ioc.RegisterType<IStrategy, TypeBStrategy>("TypeB", new InjectionConstructor("TypeB", typeof(ITypeBBusinessLogic), typeof(ITypeBApplicationLogic)));
c = ioc.Resolve<Context>();
c.Run();
Console.WriteLine("nPress enter to exit...");
Console.ReadLine();
}
And here was my output:
Mock DI Example:
[Mock] Do Business Logic for Type A
[Mock] Do Application Logic for Type A
[Mock] Do Business Logic for Type B
[Mock] Do Application Logic for Type B
Unmocked DI Example:
Do Business Logic for Type A
Do Application Logic for Type A
Do Business Logic for Type B
Do Application Logic for Type B
Press enter to exit...
This isn't the only way to solve the problem, but I think this most directly matches how you have structured your code in the OP. Hope this helps :)
EDIT: Here is one alternative to the above which I think you should consider. It will cut down on your object and interface hierarchy quite a bit. NOTE: you'll need to make the StrategyBase class not abstract, and expose the constructor as public.
Console.WriteLine("nAlternative DI Example: ");
ioc = new UnityContainer();
ioc.RegisterType<IBusinessLogic, TypeABusinessLogic>("TypeA");
ioc.RegisterType<IApplicationLogic, TypeAApplicationLogic>("TypeA");
ioc.RegisterType<IStrategy, StrategyBase>("TypeA", new InjectionConstructor("TypeA", new ResolvedParameter<IBusinessLogic>("TypeA"), new ResolvedParameter<IApplicationLogic>("TypeA") ));
ioc.RegisterType<IBusinessLogic, TypeBBusinessLogic>("TypeB");
ioc.RegisterType<IApplicationLogic, TypeBApplicationLogic>("TypeB");
ioc.RegisterType<IStrategy, StrategyBase>("TypeB", new InjectionConstructor("TypeB", new ResolvedParameter<IBusinessLogic>("TypeB"), new ResolvedParameter<IApplicationLogic>("TypeB")));
c = ioc.Resolve<Context>();
c.Run();
Since your classes and the token interfaces don't actually provide you any functionality, they only serve as a means of differentiating the specific implementations. But DI containers already have a simple means of doing this: strings. In Unity you can use the same string for different types, like above. You can use this to delineate which specific implementations go together. This is my recommendation :)
1
Thanks Ryan for your help. The token interface idea help me solved the problem
– TrBaPhong
Nov 9 at 19:40
add a comment |
up vote
1
down vote
accepted
up vote
1
down vote
accepted
So I thought of a few ways to approach this, but I think the cleanest way is to just introduce some token interfaces. A token interface is one which doesn't add any properties or functionality. For instance:
interface IBusinessLogic
{
void DoBusinessLogic();
}
interface ITypeABusinessLogic : IBusinessLogic { }
interface ITypeBBusinessLogic : IBusinessLogic { }
interface IApplicationLogic
{
void DoApplicationLogic();
}
interface ITypeAApplicationLogic : IApplicationLogic { }
interface ITypeBApplicationLogic : IApplicationLogic { }
Next we adjust the classes to implement the relevant token interface:
class TypeABusinessLogic : ITypeABusinessLogic
{
public virtual void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type A");
}
}
class TypeBBusinessLogic : ITypeBBusinessLogic
{
public virtual void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type B");
}
}
class TypeAApplicationLogic : ITypeAApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type A");
}
}
class TypeBApplicationLogic : ITypeBApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type B");
}
}
We can similarly create mock classes by implementing the relevant token interface:
class MockTypeABusinessLogic : ITypeABusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("[Mock] Do Business Logic for Type A");
}
}
class MockTypeBBusinessLogic : ITypeBBusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("[Mock] Do Business Logic for Type B");
}
}
class MockTypeAApplicationLogic : ITypeAApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("[Mock] Do Application Logic for Type A");
}
}
class MockTypeBApplicationLogic : ITypeBApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("[Mock] Do Application Logic for Type B");
}
}
I also modified the IStrategy interface to make injection with Unity a little easier, giving each strategy a Name property (you don't need to do this):
interface IStrategy
{
string Name { get; }
void DoWork();
}
abstract class StrategyBase : IStrategy
{
private IBusinessLogic _businessLogic;
private IApplicationLogic _applicationLogic;
public string Name { get; private set; }
protected StrategyBase(String name, IBusinessLogic businessLogic, IApplicationLogic applicationLogic)
{
this.Name = name;
_businessLogic = businessLogic;
_applicationLogic = applicationLogic;
}
public void DoWork()
{
_businessLogic.DoBusinessLogic();
_applicationLogic.DoApplicationLogic();
}
}
class TypeAStrategy : StrategyBase
{
public TypeAStrategy(String name, ITypeABusinessLogic businessLogic, ITypeAApplicationLogic applicationLogic) : base(name, businessLogic, applicationLogic)
{ }
}
class TypeBStrategy : StrategyBase
{
public TypeBStrategy(String name, ITypeBBusinessLogic businessLogic, ITypeBApplicationLogic applicationLogic) : base(name, businessLogic, applicationLogic)
{ }
}
Using Unity I wrote the following program to test the registrations:
class Context
{
private Dictionary<string, IStrategy> _strategyFactory = new Dictionary<string, IStrategy>();
public Context(IStrategy strategies)
{
foreach (var s in strategies)
{
_strategyFactory.Add(s.Name, s);
}
}
public void Run()
{
string userInput = "TypeA";
IStrategy strategy = _strategyFactory[userInput];
strategy.DoWork();
userInput = "TypeB";
strategy = _strategyFactory[userInput];
strategy.DoWork();
}
}
class Program
{
static void Main(string args)
{
Console.WriteLine("Mock DI Example: ");
UnityContainer ioc = new UnityContainer();
ioc.RegisterType<ITypeABusinessLogic, MockTypeABusinessLogic>();
ioc.RegisterType<ITypeAApplicationLogic, MockTypeAApplicationLogic>();
ioc.RegisterType<ITypeBBusinessLogic, MockTypeBBusinessLogic>();
ioc.RegisterType<ITypeBApplicationLogic, MockTypeBApplicationLogic>();
ioc.RegisterType<IStrategy, TypeAStrategy>("TypeA", new InjectionConstructor("TypeA", typeof(ITypeABusinessLogic), typeof(ITypeAApplicationLogic)));
ioc.RegisterType<IStrategy, TypeBStrategy>("TypeB", new InjectionConstructor("TypeB", typeof(ITypeBBusinessLogic), typeof(ITypeBApplicationLogic)));
Context c = ioc.Resolve<Context>();
c.Run();
Console.WriteLine("nUnmocked DI Example: ");
ioc = new UnityContainer();
ioc.RegisterType<ITypeABusinessLogic, TypeABusinessLogic>();
ioc.RegisterType<ITypeAApplicationLogic, TypeAApplicationLogic>();
ioc.RegisterType<ITypeBBusinessLogic, TypeBBusinessLogic>();
ioc.RegisterType<ITypeBApplicationLogic, TypeBApplicationLogic>();
ioc.RegisterType<IStrategy, TypeAStrategy>("TypeA", new InjectionConstructor("TypeA", typeof(ITypeABusinessLogic), typeof(ITypeAApplicationLogic)));
ioc.RegisterType<IStrategy, TypeBStrategy>("TypeB", new InjectionConstructor("TypeB", typeof(ITypeBBusinessLogic), typeof(ITypeBApplicationLogic)));
c = ioc.Resolve<Context>();
c.Run();
Console.WriteLine("nPress enter to exit...");
Console.ReadLine();
}
And here was my output:
Mock DI Example:
[Mock] Do Business Logic for Type A
[Mock] Do Application Logic for Type A
[Mock] Do Business Logic for Type B
[Mock] Do Application Logic for Type B
Unmocked DI Example:
Do Business Logic for Type A
Do Application Logic for Type A
Do Business Logic for Type B
Do Application Logic for Type B
Press enter to exit...
This isn't the only way to solve the problem, but I think this most directly matches how you have structured your code in the OP. Hope this helps :)
EDIT: Here is one alternative to the above which I think you should consider. It will cut down on your object and interface hierarchy quite a bit. NOTE: you'll need to make the StrategyBase class not abstract, and expose the constructor as public.
Console.WriteLine("nAlternative DI Example: ");
ioc = new UnityContainer();
ioc.RegisterType<IBusinessLogic, TypeABusinessLogic>("TypeA");
ioc.RegisterType<IApplicationLogic, TypeAApplicationLogic>("TypeA");
ioc.RegisterType<IStrategy, StrategyBase>("TypeA", new InjectionConstructor("TypeA", new ResolvedParameter<IBusinessLogic>("TypeA"), new ResolvedParameter<IApplicationLogic>("TypeA") ));
ioc.RegisterType<IBusinessLogic, TypeBBusinessLogic>("TypeB");
ioc.RegisterType<IApplicationLogic, TypeBApplicationLogic>("TypeB");
ioc.RegisterType<IStrategy, StrategyBase>("TypeB", new InjectionConstructor("TypeB", new ResolvedParameter<IBusinessLogic>("TypeB"), new ResolvedParameter<IApplicationLogic>("TypeB")));
c = ioc.Resolve<Context>();
c.Run();
Since your classes and the token interfaces don't actually provide you any functionality, they only serve as a means of differentiating the specific implementations. But DI containers already have a simple means of doing this: strings. In Unity you can use the same string for different types, like above. You can use this to delineate which specific implementations go together. This is my recommendation :)
So I thought of a few ways to approach this, but I think the cleanest way is to just introduce some token interfaces. A token interface is one which doesn't add any properties or functionality. For instance:
interface IBusinessLogic
{
void DoBusinessLogic();
}
interface ITypeABusinessLogic : IBusinessLogic { }
interface ITypeBBusinessLogic : IBusinessLogic { }
interface IApplicationLogic
{
void DoApplicationLogic();
}
interface ITypeAApplicationLogic : IApplicationLogic { }
interface ITypeBApplicationLogic : IApplicationLogic { }
Next we adjust the classes to implement the relevant token interface:
class TypeABusinessLogic : ITypeABusinessLogic
{
public virtual void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type A");
}
}
class TypeBBusinessLogic : ITypeBBusinessLogic
{
public virtual void DoBusinessLogic()
{
Console.WriteLine("Do Business Logic for Type B");
}
}
class TypeAApplicationLogic : ITypeAApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type A");
}
}
class TypeBApplicationLogic : ITypeBApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("Do Application Logic for Type B");
}
}
We can similarly create mock classes by implementing the relevant token interface:
class MockTypeABusinessLogic : ITypeABusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("[Mock] Do Business Logic for Type A");
}
}
class MockTypeBBusinessLogic : ITypeBBusinessLogic
{
public void DoBusinessLogic()
{
Console.WriteLine("[Mock] Do Business Logic for Type B");
}
}
class MockTypeAApplicationLogic : ITypeAApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("[Mock] Do Application Logic for Type A");
}
}
class MockTypeBApplicationLogic : ITypeBApplicationLogic
{
public void DoApplicationLogic()
{
Console.WriteLine("[Mock] Do Application Logic for Type B");
}
}
I also modified the IStrategy interface to make injection with Unity a little easier, giving each strategy a Name property (you don't need to do this):
interface IStrategy
{
string Name { get; }
void DoWork();
}
abstract class StrategyBase : IStrategy
{
private IBusinessLogic _businessLogic;
private IApplicationLogic _applicationLogic;
public string Name { get; private set; }
protected StrategyBase(String name, IBusinessLogic businessLogic, IApplicationLogic applicationLogic)
{
this.Name = name;
_businessLogic = businessLogic;
_applicationLogic = applicationLogic;
}
public void DoWork()
{
_businessLogic.DoBusinessLogic();
_applicationLogic.DoApplicationLogic();
}
}
class TypeAStrategy : StrategyBase
{
public TypeAStrategy(String name, ITypeABusinessLogic businessLogic, ITypeAApplicationLogic applicationLogic) : base(name, businessLogic, applicationLogic)
{ }
}
class TypeBStrategy : StrategyBase
{
public TypeBStrategy(String name, ITypeBBusinessLogic businessLogic, ITypeBApplicationLogic applicationLogic) : base(name, businessLogic, applicationLogic)
{ }
}
Using Unity I wrote the following program to test the registrations:
class Context
{
private Dictionary<string, IStrategy> _strategyFactory = new Dictionary<string, IStrategy>();
public Context(IStrategy strategies)
{
foreach (var s in strategies)
{
_strategyFactory.Add(s.Name, s);
}
}
public void Run()
{
string userInput = "TypeA";
IStrategy strategy = _strategyFactory[userInput];
strategy.DoWork();
userInput = "TypeB";
strategy = _strategyFactory[userInput];
strategy.DoWork();
}
}
class Program
{
static void Main(string args)
{
Console.WriteLine("Mock DI Example: ");
UnityContainer ioc = new UnityContainer();
ioc.RegisterType<ITypeABusinessLogic, MockTypeABusinessLogic>();
ioc.RegisterType<ITypeAApplicationLogic, MockTypeAApplicationLogic>();
ioc.RegisterType<ITypeBBusinessLogic, MockTypeBBusinessLogic>();
ioc.RegisterType<ITypeBApplicationLogic, MockTypeBApplicationLogic>();
ioc.RegisterType<IStrategy, TypeAStrategy>("TypeA", new InjectionConstructor("TypeA", typeof(ITypeABusinessLogic), typeof(ITypeAApplicationLogic)));
ioc.RegisterType<IStrategy, TypeBStrategy>("TypeB", new InjectionConstructor("TypeB", typeof(ITypeBBusinessLogic), typeof(ITypeBApplicationLogic)));
Context c = ioc.Resolve<Context>();
c.Run();
Console.WriteLine("nUnmocked DI Example: ");
ioc = new UnityContainer();
ioc.RegisterType<ITypeABusinessLogic, TypeABusinessLogic>();
ioc.RegisterType<ITypeAApplicationLogic, TypeAApplicationLogic>();
ioc.RegisterType<ITypeBBusinessLogic, TypeBBusinessLogic>();
ioc.RegisterType<ITypeBApplicationLogic, TypeBApplicationLogic>();
ioc.RegisterType<IStrategy, TypeAStrategy>("TypeA", new InjectionConstructor("TypeA", typeof(ITypeABusinessLogic), typeof(ITypeAApplicationLogic)));
ioc.RegisterType<IStrategy, TypeBStrategy>("TypeB", new InjectionConstructor("TypeB", typeof(ITypeBBusinessLogic), typeof(ITypeBApplicationLogic)));
c = ioc.Resolve<Context>();
c.Run();
Console.WriteLine("nPress enter to exit...");
Console.ReadLine();
}
And here was my output:
Mock DI Example:
[Mock] Do Business Logic for Type A
[Mock] Do Application Logic for Type A
[Mock] Do Business Logic for Type B
[Mock] Do Application Logic for Type B
Unmocked DI Example:
Do Business Logic for Type A
Do Application Logic for Type A
Do Business Logic for Type B
Do Application Logic for Type B
Press enter to exit...
This isn't the only way to solve the problem, but I think this most directly matches how you have structured your code in the OP. Hope this helps :)
EDIT: Here is one alternative to the above which I think you should consider. It will cut down on your object and interface hierarchy quite a bit. NOTE: you'll need to make the StrategyBase class not abstract, and expose the constructor as public.
Console.WriteLine("nAlternative DI Example: ");
ioc = new UnityContainer();
ioc.RegisterType<IBusinessLogic, TypeABusinessLogic>("TypeA");
ioc.RegisterType<IApplicationLogic, TypeAApplicationLogic>("TypeA");
ioc.RegisterType<IStrategy, StrategyBase>("TypeA", new InjectionConstructor("TypeA", new ResolvedParameter<IBusinessLogic>("TypeA"), new ResolvedParameter<IApplicationLogic>("TypeA") ));
ioc.RegisterType<IBusinessLogic, TypeBBusinessLogic>("TypeB");
ioc.RegisterType<IApplicationLogic, TypeBApplicationLogic>("TypeB");
ioc.RegisterType<IStrategy, StrategyBase>("TypeB", new InjectionConstructor("TypeB", new ResolvedParameter<IBusinessLogic>("TypeB"), new ResolvedParameter<IApplicationLogic>("TypeB")));
c = ioc.Resolve<Context>();
c.Run();
Since your classes and the token interfaces don't actually provide you any functionality, they only serve as a means of differentiating the specific implementations. But DI containers already have a simple means of doing this: strings. In Unity you can use the same string for different types, like above. You can use this to delineate which specific implementations go together. This is my recommendation :)
edited Nov 9 at 10:18
answered Nov 9 at 6:21
Ryan Pierce Williams
43719
43719
1
Thanks Ryan for your help. The token interface idea help me solved the problem
– TrBaPhong
Nov 9 at 19:40
add a comment |
1
Thanks Ryan for your help. The token interface idea help me solved the problem
– TrBaPhong
Nov 9 at 19:40
1
1
Thanks Ryan for your help. The token interface idea help me solved the problem
– TrBaPhong
Nov 9 at 19:40
Thanks Ryan for your help. The token interface idea help me solved the problem
– TrBaPhong
Nov 9 at 19:40
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53216558%2fhow-to-use-di-container-to-resolve-dependencies-in-strategy-pattern%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
You don't use the DI container to resolve dynamic input from the user (Any injection should be complete after bootstrapping). You could use factories. DI could be used to inject the available factories, along with the names to use for those factories. For example, using Unity you could pull the factory registrations out into a config file. You could then modify the factories that are registered from the config file without recompiling your program, and give each factory a unique name. You could supply any name you wanted for each individual factory, doesn't need to be the class name.
– Ryan Pierce Williams
Nov 8 at 21:48
@Ryan: Can you provide more details on how to register dependencies for my strategy. Any example code (even in Unity) is really appreciated. I add my ContainerBuilder code to make it more clear.
– TrBaPhong
Nov 8 at 22:05
If someone else doesn't do it before I can, I'll put together an example tonight. At any rate, your current hierarchy doesn't require intermediate interfaces for each strategy. Your strategies aren't adding anything new in terms of functionality or in terms of properties, so your base IStrategy interface is all you need for mocking purposes.
– Ryan Pierce Williams
Nov 8 at 22:23
What do you mean "intermediate interfaces for each strategy"? Are you talking about IBusinessLogic, IApplicationLogic? I think it necessary because I wanna separate different logic categories into different classes (TypeABusinessLogic and TypeAApplicationLogic handle different logic). It helps my achieve Single Reponsibility.
– TrBaPhong
Nov 9 at 3:13
I mean that you don't need an ITypeAStrategy or ITypeBStrategy interface. The strategies don't add any functionality/properties so you can mock them both just using the base IStrategy interface.
– Ryan Pierce Williams
Nov 9 at 5:07