Ich möchte sichergehen, dass ich das Konzept der Abhängigkeitsinjektion (DI) verstehe. Nun, ich verstehe das Konzept tatsächlich, DI ist nicht kompliziert: Sie erstellen eine Schnittstelle und übergeben dann die Implementierung meiner Schnittstelle an die Klasse, die sie verwendet. Die übliche Methode zum Übergeben ist der Konstruktor. Sie können ihn jedoch auch per Setter oder einer anderen Methode übergeben.
Ich bin mir nicht sicher, wann ich DI verwenden soll.
Verwendung 1: Natürlich erscheint die Verwendung von DI für den Fall, dass Ihre Schnittstelle mehrfach implementiert ist, logisch. Sie haben ein Repository für Ihren SQL Server und ein anderes für Ihre Oracle-Datenbank. Beide teilen sich die gleiche Schnittstelle und Sie "injizieren" (dies ist der verwendete Begriff) diejenige, die Sie zur Laufzeit möchten. Dies ist sogar nicht DI, dies ist hier die grundlegende OO-Programmierung.
Verwendung 2: Wenn Sie eine Geschäftsschicht mit vielen Diensten mit all ihren spezifischen Methoden haben, scheint es die gute Praxis zu sein, für jeden Dienst eine Schnittstelle zu erstellen und die Implementierung auch dann einzufügen, wenn diese eindeutig ist. Weil dies besser für die Wartung ist. Dies ist diese zweite Verwendung, die ich nicht verstehe.
Ich habe ungefähr 50 Businessklassen. Nichts ist zwischen ihnen gemeinsam. Einige sind Repositorys, die Daten in 3 verschiedenen Datenbanken abrufen oder speichern. Einige lesen oder schreiben Dateien. Einige machen reine Geschäftsaktionen. Es gibt auch spezielle Validatoren und Helfer. Die Herausforderung ist die Speicherverwaltung, da einige Klassen von verschiedenen Standorten aus instanziiert werden. Ein Validator kann mehrere Repositorys und andere Validatoren aufrufen, die dieselben Repositorys erneut aufrufen können.
Beispiel: Geschäftsschicht
public class SiteService : Service, ICrud<Site>
{
public Site Read(Item item, Site site)
{
return beper4DbContext.Site
.AsNoTracking()
.SingleOrDefault(y => y.SiteId == site.Id && y.ItemId == item.Id)
}
public Site Read(string itemCode, string siteCode)
{
using (var itemService = new ItemService())
{
var item = itemService.Read(itemCode);
return Read(item, site);
}
}
}
public class ItemSiteService : Service, ICrud<Site>
{
public ItemSite Read(Item item, Site site)
{
return beper4DbContext.ItemSite
.AsNoTracking()
.SingleOrDefault(y => y.SiteId == site.Id && y.ItemId == item.Id)
}
public ItemSite Read(string itemCode, string siteCode)
{
using (var itemService = new ItemService())
using (var siteService = new SiteService())
{
var item = itemService.Read(itemCode);
var site = siteService.Read(itemCode, siteCode);
return Read(item, site);
}
}
}
Regler
public class ItemSiteController : BaseController
{
[Route("api/Item/{itemCode}/ItemSite/{siteCode}")]
public IHttpActionResult Get(string itemCode, string siteCode)
{
using (var service = new ItemSiteService())
{
var itemSite = service.Read(itemCode, siteCode);
return Ok(itemSite);
}
}
}
Dieses Beispiel ist sehr einfach, aber Sie sehen, wie ich leicht zwei Instanzen von itemService erstellen kann, um eine itemSite zu erhalten. Dann kommt auch jeder Dienst mit seinem DB-Kontext. Dieser Aufruf erstellt also 3 DbContext. 3 Verbindungen.
Meine erste Idee war, Singleton zu erstellen, um all diesen Code wie unten umzuschreiben. Der Code ist besser lesbar und am wichtigsten ist, dass das Singleton-System nur eine Instanz jedes verwendeten Dienstes erstellt und beim ersten Aufruf erstellt. Perfekt, außer dass ich immer noch einen anderen Kontext habe, aber ich kann das gleiche System für meine Kontexte verwenden. So fertig.
Geschäftsschicht
public class SiteService : Service, ICrud<Site>
{
public Site Read(Item item, Site site)
{
return beper4DbContext.Site
.AsNoTracking()
.SingleOrDefault(y => y.SiteId == site.Id && y.ItemId == item.Id)
}
public Site Read(string itemCode, string siteCode)
{
var item = ItemService.Instance.Read(itemCode);
return Read(item, site);
}
}
public class ItemSiteService : Service, ICrud<Site>
{
public ItemSite Read(Item item, Site site)
{
return beper4DbContext.ItemSite
.AsNoTracking()
.SingleOrDefault(y => y.SiteId == site.Id && y.ItemId == item.Id)
}
public ItemSite Read(string itemCode, string siteCode)
{
var item = ItemService.Instance.Read(itemCode);
var site = SiteService.Instance.Read(itemCode, siteCode);
return Read(item, site);
}
}
Regler
public class ItemSiteController : BaseController
{
[Route("api/Item/{itemCode}/ItemSite/{siteCode}")]
public IHttpActionResult Get(string itemCode, string siteCode)
{
var itemSite = service.Instance.Read(itemCode, siteCode);
return Ok(itemSite);
}
}
Einige Leute sagen mir nach guter Praxis, ich sollte DI mit einer einzelnen Instanz verwenden, und Singleton ist eine schlechte Praxis. Ich sollte für jede Business Class eine Schnittstelle erstellen und diese mithilfe eines DI-Containers instanziieren. "Ja wirklich?" Dieser DI vereinfacht meinen Code. Kaum zu glauben.