问题
I asked a more general question a minute ago: How to organize DI Framework usage in an application?, and the feedback I got was that I was using a Service Locator Pattern rather than true DI as is pointed out by Martin Fowler here: http://martinfowler.com/articles/injection.html
Actually, I read that article just the other day, but apparently haven't quite grasped it.
So let's say I have the following code:
interface ICardReader
{
string GetInfo();
void SetDebugMode(bool value);
void Initialize(string accountToken);
void ShowAmount(string amount);
void Close();
ICreditCardInfo GetCardInfo();
}
public class MagTekIPAD: ICardReader
{
public ICreditCardInfo GetCardInfo()
{
var card = GetCardDataFromDevice();
// apparently the following line is wrong?
var ccInfo = Inject<ICreditCardInfo>.New();
ccInfo.Track1 = MakeHex(card.EncTrack1);
ccInfo.Track2 = MakeHex(card.EncTrack2);
ccInfo.MagSignature = MakeHex(card.EncMP);
ccInfo.MagSwipeKeySN = MakeHex(card.KSN);
ccInfo.MagSignatureStatus = MakeHex(card.MPSts);
ccInfo.MagDeviceSN = ipad.Serial;
ccInfo.MSREncryptType = "MAGENSA_V5";
return ccInfo;
}
// Other implementation details here ...
}
In this example I could inject the dependency into the constructor—and I think that's the correct way to fix 'this' scenario.
But what if I actually need to create an unknown number of the object in question (or are there any other legitimate reason I'd have a need to create the dependency on the fly in the class)?
回答1:
This example gives me the impression that you try to create a data transfer object namingly ICreditCardInfo
using an IoC container. Such objects should not have any real dependencies like a service. The proper way to create DTOs is to use the new
operator:
return new CreditCardInfo(
MakeHex(card.EncTrack1),
MakeHex(card.EncTrack2),
MakeHex(card.EncMP),
MakeHex(card.KSN),
MakeHex(card.MPSts),
ipad.Serial,
"MAGENSA_V5");
回答2:
Inject a factory for ICreditCardInfo
objects into the constructor of MagTekIPAD
public class MagTekIPAD : ICardReader
{
private readonly Func<ICreditCardInfo> factory;
public MagTekIPAD(Func<ICreditCardInfo> factory)
{
this.factory = factory;
}
public ICreditCardInfo GetCardInfo()
{
var info = factory();
// ...
return info;
}
}
Several containers can auto-generate Func<T>
delegates if they know how to create instances of T
so you don't have to define factory interfaces or abstract factory classes.
回答3:
As Fowler pointed out, Service Locator is the more direct approach and is less error prone.
Some Dependency Injection frameworks require you to declare whether you are dealing with Singleton or they can have different lifetimes.
来源:https://stackoverflow.com/questions/9373004/how-to-turn-this-service-locator-pattern-into-true-dependency-injection-pattern