Diese Frage ergibt sich aus einem Beitrag von Jeffery Palermo ist wie http://jeffreypalermo.com/blog/constructor-over-injection-anti-pattern/IoC und Konstruktor über Injektion anti-Musterauflösung
In seinem Posten um verzweigten Code und Dependency Injection zu bekommen, hat Jeffery eine Klasse (public class OrderProcessor : IOrderProcessor
), die 2 Schnittstellen im Konstruktor benötigt. Einer ist ein Validator IOrderValidator
und eine IOrderShipper
Schnittstelle. Sein Methodencode verzweigt nach nur Methoden auf der IOrderValidator
Schnittstelle und verwendet nie etwas auf der IOrderShipper
Schnittstelle.
Er schlägt vor, eine Factory zu erstellen, die eine statische Methode aufruft, um den Delegaten der Schnittstelle zu erhalten. Er erstellt in seinem refaktorierten Code ein neues Objekt, das unnötig erscheint.
Ich denke, der Kern des Problems ist, dass wir IoC verwenden, um alle unsere Objekte zu erstellen, unabhängig davon, ob sie verwendet werden oder nicht. Wenn Sie ein Objekt mit 2 Schnittstellen instanziieren und Code haben, der verzweigen könnte, um keinen von ihnen zu verwenden, wie gehen Sie damit um?
In diesem Beispiel gehen wir davon _validator.Validate(order)
immer false zurückgibt und die IOrderShipper.Ship()
Methode aufgerufen wird nie.
Originalcode:
public class OrderProcessor : IOrderProcessor
{
private readonly IOrderValidator _validator;
private readonly IOrderShipper _shipper;
public OrderProcessor(IOrderValidator validator, IOrderShipper shipper)
{
_validator = validator;
_shipper = shipper;
}
public SuccessResult Process(Order order)
{
bool isValid = _validator.Validate(order);
if (isValid)
{
_shipper.Ship(order);
}
return CreateStatus(isValid);
}
private SuccessResult CreateStatus(bool isValid)
{
return isValid ? SuccessResult.Success : SuccessResult.Failed;
}
}
public class OrderShipper : IOrderShipper
{
public OrderShipper()
{
Thread.Sleep(TimeSpan.FromMilliseconds(777));
}
public void Ship(Order order)
{
//ship the order
}
}
Überarbeitete-Code
public class OrderProcessor : IOrderProcessor
{
private readonly IOrderValidator _validator;
public OrderProcessor(IOrderValidator validator)
{
_validator = validator;
}
public SuccessResult Process(Order order)
{
bool isValid = _validator.Validate(order);
if (isValid)
{
IOrderShipper shipper = new OrderShipperFactory().GetDefault();
shipper.Ship(order);
}
return CreateStatus(isValid);
}
private SuccessResult CreateStatus(bool isValid)
{
return isValid ? SuccessResult.Success : SuccessResult.Failed;
}
}
public class OrderShipperFactory
{
public static Func<IOrderShipper> CreationClosure;
public IOrderShipper GetDefault()
{
return CreationClosure(); //executes closure
}
}
Und hier ist die Methode, die diese Fabrik beim Start-up-Zeit (global.asax für ASP.NET) konfiguriert:
private static void ConfigureFactories()
{
OrderShipperFactory.CreationClosure =
() => ObjectFactory.GetInstance<IOrderShipper>();
}
vermutlich sollte der refaktorierte Code nicht den IOrderShipper im Konstruktor übernehmen ... sonst ist der Punkt des Refactorings? –
In dem Post, den Sie verlinkt haben, hat sein refaktorierter Code keinen IOrderShipper im Konstruktor, aber in Ihrem refaktorierten Code ist dies der Fall. Ich stimme Jeffrey Pallermo in diesem Fall nicht unbedingt zu, aber es ist ein wichtiger Unterschied zwischen Ihrer Implementierung und seiner. –
Ich denke, ich habe den Code falsch kopiert. Ich dachte, es wäre einfacher, alles hier zu setzen = (Korrigiert –