Reputation: 2453
I have a class with the following structure
class Measure
{
public MeasureType measureType { get; set; }
public readonly IMeasureService _service ;
public Measure(IMeasureService service)
{
_service = service;
}
public Calculate()
{
_service.Calculate(this);
}
}
So i have different implementation of MeasureService for different measureTypes. Is it possible to use StructureMap to inject the corresponding MeasureService based on the measureType.
MeasureType is just an enum type and will never get changed throughout the instance.
Upvotes: 2
Views: 405
Reputation: 40526
StructureMap cannot be instructed to do that for a simple reason:
measureType
property cannot be set.IMeasureService
dependency at a later time, because it's readonly
(and should probably be private
as well)Therefore, the solutions to this problem have more to do with the design of your classes than with StructureMap.
Here are the solutions I would typically choose in such a scenario:
IMeasureService
implementation to a different component.The component could, for example, be called MeasureServiceFactory
and have the following implementation:
public class MeasureServiceFactory
{
private readonly Func<MeasureServiceType1> _type1Service;
private readonly Func<MeasureServiceType2> _type2Service;
public MeasureServiceFactory(
Func<MeasureServiceType1> type1Service,
Func<MeasureServiceType2> type2Service)
{
_type1Service = type1Service;
_type2Service = type2Service;
}
public IMeasureService GetServiceForType(MeasureType type)
{
switch (type)
{
case MeasureType.Type1:
return _type1Service();
case MeasureType.Type2:
return _type2Service();
default:
throw new ApplicationException("Unexpected measure type!");
}
}
}
Note that StructureMap will automatically inject the two Func
s with appropriate calls to the container's GetInstance()
method in order to properly resolve the required service.
Now, the Measure
class will no longer have a direct IMeasureService
dependency, but will depend on the factory instead:
public class Measure
{
public MeasureType measureType { get; set; }
private readonly MeasureServiceFactory _measureServiceFactory;
public Measure(MeasureServiceFactory measureServiceFactory)
{
_measureServiceFactory = measureServiceFactory;
}
public void Calculate()
{
var service = _measureServiceFactory.GetServiceForType(measureType);
service.Calculate(this);
}
}
Note that no StructureMap configuration is required. The container will be able to resolve everything correctly.
Measure
class untouched, you could make the MeasureServiceFactory
implement the IMeasureService
interface:public class MeasureServiceFactory : IMeasureService
{
private readonly Func<MeasureServiceType1> _type1Service;
private readonly Func<MeasureServiceType2> _type2Service;
public MeasureServiceFactory(
Func<MeasureServiceType1> type1Service,
Func<MeasureServiceType2> type2Service)
{
_type1Service = type1Service;
_type2Service = type2Service;
}
public void Calculate(Measure measure)
{
var service = GetServiceForType(measure.measureType);
service.Calculate(measure);
}
private IMeasureService GetServiceForType(MeasureType type)
{
switch (type)
{
case MeasureType.Type1:
return _type1Service();
case MeasureType.Type2:
return _type2Service();
default:
throw new ApplicationException("Unexpected measure type!");
}
}
}
Now, with your original Measure
class, only this SM configuration is required to ake everything work:
x.For<IMeasureService>().Use<MeasureServiceFactory>();
IMeasureService
implementors is not very complicated, consider putting it in a single class and perform different things depending on the measureType
of the Measure
object (which you already have access to).I know, this seems like a step back, but there are some cases in which I prefer to do just that: when the business logic is not overly complex and pretty unlikely to change.
Upvotes: 2