2010-11-06 44 views
6

Tôi biết giao diện không thể xác định hàm tạo. Thực hành tốt nhất để buộc tất cả các lớp thực hiện một giao diện là gì, để nhận được các phụ thuộc của chúng trong một hợp đồng thống nhất. Tôi biết ints có thể tiêm phụ thuộc vào các đối tượng thông qua tài sản, nhưng đi qua chúng thông qua các nhà xây dựng có ý nghĩa hơn với tôi. Làm thế nào để DI sau đó?Làm thế nào để tiêm phụ thuộc vào các lớp học thực hiện một giao diện?

Trả lời

0

Chúng ta đều biết điều này là có thể bằng nhiều phương pháp khác nhau, nhưng một cái gì đó có ý nghĩa được chào đón nhiều hơn chắc chắn.Tôi định nghĩa một số set-only tài sản, sau đó các đối tượng có trách nhiệm giữ một tham chiếu đến những gì đang được truyền cho nó:

public interface IBlogRepository 
{ 
    ISession Session { set; } 
} 

class BlogRepository : IBlogRepository 
{ 
    private ISession m_session; 

    ISession Session 
    { 
     set { m_session = value; } 
    } 
} 

Bằng cách này mỗi lớp thực hiện giao diện biết rằng set-only tài sản là một dependency injection, vì set-only tài sản này hiếm khi được sử dụng. Tôi không chắc liệu phương pháp này có được gọi là good practice hay không, nhưng đối với tôi nó là, từ bây giờ.

+0

Gắn bó cứng nhắc với chỉ một cách để xác định các phụ thuộc là loại bỏ các lựa chọn thiết kế. Các lựa chọn khác không phải là xấu, chúng chỉ khác nhau. –

+0

Với thiết kế này, bạn yêu cầu các lớp dẫn xuất để xác định các thuộc tính, nhưng bạn không yêu cầu người dùng của lớp điền vào các phụ thuộc. Nếu người dùng instantiates lớp của bạn, không điền vào các thuộc tính, và gọi một phương pháp, bạn không thể ném. Làm như vậy sẽ vi phạm hợp đồng tiềm ẩn do giao diện xác định. Hai cách duy nhất để * yêu cầu * một phụ thuộc được điền vào là các tham số của hàm tạo và phương thức. –

3

Một tùy chọn là tạo phương thức trên giao diện để khởi tạo. Phương thức này có thể chấp nhận tất cả các phụ thuộc bắt buộc.

Cái gì như:

void Configure(dependency1 value, etc.); 

Tất nhiên, có rất nhiều lựa chọn để làm kiểu này khởi tạo và DI sử dụng một khuôn khổ. Có rất nhiều tùy chọn để lựa chọn.

Scott Hanselman có danh sách tốt here.

2

những gì bạn cần làm là để có tất cả các triển khai giao diện của bạn phân lớp một lớp với một hàm tạo bất kỳ trạng thái nào cần được tiêm. vì các lớp con cần thực hiện cuộc gọi cơ bản, trong hàm tạo của chúng, các ràng buộc của bạn được duy trì tự động.

lúc đầu điều này có vẻ giống như một mô hình kỳ lạ, nhưng chúng tôi sử dụng tất cả thời gian trong giải pháp doanh nghiệp của chúng tôi, vì vậy tôi đảm bảo :-) lành mạnh của nó

7

Tôi biết bạn nói bạn muốn có một hợp đồng ổn định. Nhưng một lợi thế để không cung cấp một giao diện ổn định là phụ thuộc của bạn sau đó có thể thay đổi một cách hoang dại với hiện thực khác nhau, trong đó sẽ giảm nối:

public interface IBlogRepository 
{ 
    IEnumerable<Entry> GetEntries(int pageId, int pageCount); 
} 

class BlogDatabase : IBlogRepository 
{ 
    public BlogDatabase(ISession session) 
    { 
     this.session = session; 
    } 

    public IEnumerable<Entry> GetEntries(int pageId, int pageCount) 
    { 
     // Not that you should implement your queries this way... 
     var query = session.CreateQuery("from BlogEntry"); 
     return query.Skip(pageId * pageCount).Take(pageCount); 
    } 

    private ISession session; 
} 

Như bạn đã nói, bạn cũng có thể thực hiện phụ thuộc như tài sản (hoặc đối số), nhưng điều này sẽ mã hóa cứng các phụ thuộc của bạn, thay vì làm cho chúng triển khai cụ thể. Bạn sẽ tách riêng việc triển khai phiên cụ thể của mình, nhưng bạn vẫn phải phụ thuộc vào phiên.

public interface IBlogRepository 
{ 
    ISession Session { get; set; } 
    IEnumerable<Entry> GetEntries(int pageId, int pageCount); 
    IEnumerable<Entry> GetEntriesWithSession(ISession session, 
     int pageId, int pageCount); 
} 

class BlogDatabase : IBlogRepository 
{ 
    public ISession Session { Get; set; } 

    public IEnumerable<Entry> GetEntries(int pageId, int pageCount) 
    { 
     var query = Session.CreateQuery ... 
    } 

    public IEnumerable<Entry> GetEntries(ISession session, int pageId, int pageCount) 
    { 
     var query = session.CreateQuery ... 
    } 
} 

class BlogFile : IBlogRepository 
{ 
    // ISession has to abstract a file handle. We're still okay 
    // ... 
} 

class BlogInMemory : IBlogRepository 
{ 
    // ISession abstracts nothing. 
    // Maybe a lock, at best, but the abstraction is still breaking down 
    // ... 
} 

Tiêm xây dựng sẽ chỉ hoạt động nếu bạn đang sử dụng một số loại Khuôn khổ phụ thuộc có thể xử lý việc xây dựng/cung cấp phụ thuộc cho bạn. Thuộc tính và đối số tiêm sẽ làm việc ngay cả khi không có khuôn khổ.

Tôi tin rằng cả ba đều được chấp nhận. Ít nhất một vài khung công tác phổ biến hỗ trợ cả hàm khởi tạo và thuộc tính.

Điều này có nghĩa là quyết định tùy thuộc vào bạn đối với những gì có ý nghĩa nhất đối với dự án của bạn. Giao dịch là biểu đồ phụ thuộc dễ theo dõi, so với khớp nối mạnh hơn. Quyết định chắc chắn không phải là tất cả các nhà xây dựng hoặc tất cả các tài sản/đối số, một trong hai.

Một mức trừu tượng cấp cao hơn để nghĩ đến là một lớp nhà máy trừu tượng. Bạn sẽ làm điều này nếu bạn muốn nhóm một nhóm phụ thuộc hoặc bạn cần phải tạo các phiên bản của chúng trong thời gian chạy:

public interface IInstallationFactory 
{ 
    IUser CreateRegisteredUser(Guid userSid); 
    IPackage CreateKnownPackage(Guid id); 
    IInstaller CreateInstaller(); 
} 

Các khung khác nhau cũng hỗ trợ các nhà máy trừu tượng.

+1

Đây chính xác là những gì tôi đã nói, nhưng vì vậy giải thích tốt hơn rất nhiều. +1 và xóa của riêng tôi. –

0

Giao diện không chịu trách nhiệm về các phụ thuộc. Chỉ thực hiện biết, những gì nó cần để thực hiện hợp đồng.

Có thể có một triển khai bằng cách sử dụng cơ sở dữ liệu, một hệ thống tệp khác sử dụng dữ liệu tồn tại.

Cần phải khai báo giao diện nào? Trình quản lý cơ sở dữ liệu hoặc trình quản lý hệ thống tập tin?

Các vấn đề liên quan