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)?
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");
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With