Tôi muốn chắc chắn rằng tôi hiểu khái niệm tiêm phụ thuộc (DI). Chà, tôi thực sự hiểu khái niệm, DI không phức tạp: bạn tạo một giao diện sau đó bạn chuyển việc thực hiện giao diện của tôi cho lớp sử dụng nó. Cách phổ biến để vượt qua nó là bởi constructor nhưng bạn cũng có thể truyền nó bằng setter hoặc phương thức khác.
Điều tôi không chắc là hiểu khi nào nên sử dụng DI.
Cách sử dụng 1: Tất nhiên sử dụng DI trong trường hợp bạn có nhiều triển khai giao diện của bạn có vẻ logic. Bạn có một kho lưu trữ cho Máy chủ SQL của mình, sau đó một kho lưu trữ khác cho cơ sở dữ liệu Oracle của bạn. Cả hai đều có chung giao diện và bạn "tiêm" (đây là thuật ngữ được sử dụng) giao diện bạn muốn trong thời gian chạy. Điều này thậm chí không phải là DI, đây là lập trình OO cơ bản ở đây.
Cách sử dụng 2: Khi bạn có một lớp nghiệp vụ với nhiều dịch vụ với tất cả các phương thức cụ thể, có vẻ như cách tốt nhất là tạo giao diện cho mỗi dịch vụ và cũng thực hiện việc triển khai ngay cả khi dịch vụ này là duy nhất. Bởi vì điều này là tốt hơn để bảo trì. Đây là cách sử dụng thứ hai tôi không hiểu.
Tôi có khoảng 50 lớp kinh doanh. Không có gì là phổ biến giữa họ. Một số kho lưu trữ nhận hoặc lưu dữ liệu trong 3 cơ sở dữ liệu khác nhau. Một số đọc hoặc ghi tập tin. Một số làm hành động kinh doanh thuần túy. Ngoài ra còn có trình xác nhận và trợ giúp cụ thể. Thách thức là quản lý bộ nhớ vì một số lớp được điều khiển từ các vị trí khác nhau. Trình xác thực có thể gọi một số kho lưu trữ và các trình xác nhận khác có thể gọi lại cùng một kho lưu trữ.
Ví dụ: Lớp nghiệp vụ
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);
}
}
}
Bộ điều khiển
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);
}
}
}
Ví dụ này rất cơ bản nhưng bạn thấy cách tôi có thể dễ dàng tạo 2 phiên bản của itemService để lấy itemSite. Sau đó, mỗi dịch vụ đi kèm với bối cảnh DB của mình. Vì vậy, cuộc gọi này sẽ tạo ra 3 DbContext. 3 kết nối.
Ý tưởng đầu tiên của tôi là tạo ra singleton để viết lại tất cả mã này như dưới đây. Mã dễ đọc hơn và quan trọng nhất là hệ thống singleton chỉ tạo một phiên bản của mỗi dịch vụ được sử dụng và tạo nó trong cuộc gọi đầu tiên. Hoàn hảo, ngoại trừ tôi vẫn có bối cảnh khác biệt nhưng tôi có thể làm cùng một hệ thống cho bối cảnh của mình. Vậy là xong.
Lớp kinh doanh
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);
}
}
Bộ điều khiển
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);
}
}
Một số người nói với tôi theo thông lệ tốt, tôi nên sử dụng DI với một trường hợp duy nhất và sử dụng singleton là thực hành xấu. Tôi nên tạo một giao diện cho mỗi lớp nghiệp vụ và khởi tạo nó với sự trợ giúp của container DI. Có thật không? DI này đơn giản hóa mã của tôi. Khó tin.