Các giao diện nên mở rộng (và thực hiện như vậy các phương thức kế thừa) các giao diện khác


13

Mặc dù đây là một câu hỏi chung nhưng nó cũng cụ thể cho một vấn đề tôi hiện đang gặp phải. Tôi hiện có một giao diện được chỉ định trong giải pháp của tôi được gọi là

public interface IContextProvider
{
   IDataContext { get; set; }
   IAreaContext { get; set; }
}

Giao diện này thường được sử dụng trong suốt chương trình và do đó tôi có thể dễ dàng truy cập vào các đối tượng tôi cần. Tuy nhiên, ở mức độ khá thấp của một phần chương trình của tôi, tôi cần truy cập vào một lớp khác sẽ sử dụng IAreaContext và thực hiện một số thao tác tắt nó. Vì vậy, tôi đã tạo một giao diện nhà máy khác để thực hiện việc tạo này được gọi là:

public interface IEventContextFactory 
{
   IEventContext CreateEventContext(int eventId);
}

Tôi có một lớp thực hiện IContextProvider và được tiêm bằng NinJect. Vấn đề tôi gặp phải là khu vực tôi cần sử dụng IEventContextFactory này chỉ có quyền truy cập vào IContextProvider và chính nó sử dụng một lớp khác sẽ cần giao diện mới này. Tôi không muốn phải khởi tạo việc triển khai IEventContextFactory ở mức độ thấp và muốn làm việc với giao diện IEventContextFactory xuyên suốt. Tuy nhiên tôi cũng không muốn phải tiêm một tham số khác thông qua các hàm tạo chỉ để nó được truyền qua lớp cần nó, tức là

// example of problem
public class MyClass
{
    public MyClass(IContextProvider context, IEventContextFactory event)
    {
       _context = context;
       _event = event;
    }

    public void DoSomething() 
    {
       // the only place _event is used in the class is to pass it through
       var myClass = new MyChildClass(_event);
       myClass.PerformCalculation();      
    }
}

Vì vậy, câu hỏi chính của tôi là, điều này có thể được chấp nhận hay thậm chí là thông thường hoặc thực hành tốt để làm một cái gì đó như thế này (giao diện mở rộng giao diện khác):

public interface IContextProvider : IEventContextFactory

hoặc tôi nên xem xét các lựa chọn thay thế tốt hơn để đạt được những gì tôi cần. Nếu tôi chưa cung cấp đủ thông tin để đưa ra gợi ý cho tôi biết và tôi có thể cung cấp thêm.


2
Tôi muốn đặt lại tiêu đề câu hỏi của bạn là "Nên giao diện kế thừa giao diện" vì không có giao diện nào thực sự thực hiện bất cứ điều gì.
Jesse C. Choper

2
Ngôn ngữ thông thường là một giao diện "mở rộng" cha mẹ của nó và (khi làm như vậy) "kế thừa" các phương thức của giao diện cha mẹ, vì vậy tôi khuyên bạn nên sử dụng "mở rộng" ở đây.
Theodore Murdock

Giao diện có thể mở rộng cha mẹ, vậy tại sao nó sẽ là thực hành xấu? Nếu một giao diện hợp pháp là một siêu tập hợp của một giao diện khác thì tất nhiên nó sẽ mở rộng nó.
Robin Winslow

Câu trả lời:


10

Mặc dù các giao diện chỉ mô tả hành vi mà không có bất kỳ triển khai nào, chúng vẫn có thể tham gia vào hệ thống phân cấp thừa kế. Ví dụ, hãy tưởng tượng bạn có, nói, ý tưởng chung của a Collection. Giao diện này sẽ cung cấp một vài điều phổ biến cho tất cả các bộ sưu tập, chẳng hạn như một phương thức để lặp lại các thành viên. Sau đó, bạn có thể nghĩ về một số bộ sưu tập các đối tượng cụ thể hơn như a Listhoặc a Set. Mỗi trong số này thừa hưởng tất cả các yêu cầu hành vi của a Collection, nhưng thêm các yêu cầu bổ sung cụ thể cho loại bộ sưu tập cụ thể đó.

Bất cứ lúc nào có ý nghĩa để tạo một hệ thống phân cấp thừa kế cho các giao diện, thì bạn nên. Nếu hai giao diện sẽ luôn được tìm thấy cùng nhau, thì có lẽ chúng nên được hợp nhất.


6

Có, nhưng chỉ khi nó có ý nghĩa. Hãy tự hỏi mình những câu hỏi sau đây và nếu một hoặc nhiều áp dụng thì có thể chấp nhận kế thừa giao diện từ một giao diện khác.

  1. Giao diện A có mở rộng logic giao diện B không, ví dụ IList thêm chức năng vào ICollection.
  2. Giao diện Có cần xác định hành vi đã được chỉ định bởi giao diện khác không, ví dụ như triển khai IDis Dùng nếu nó có tài nguyên cần được dọn dẹp hoặc IEnumerable nếu nó có thể được lặp đi lặp lại.
  3. Có phải mọi triển khai giao diện A đều yêu cầu hành vi được chỉ định bởi giao diện B không?

Trong ví dụ của bạn, tôi không nghĩ nó trả lời có cho bất kỳ câu hỏi nào. Bạn có thể tốt hơn khi thêm nó như một tài sản khác:

public interface IContextProvider
{
   IDataContext DataContext { get; set; }
   IAreaContext AreaContext { get; set; }
   IEventContextFactory EventContextFactory { get; set; }
}

Làm thế nào để làm cho nó trở thành một tài sản tốt hơn so với việc mở rộng giao diện, hoặc nó chỉ là một cách khác để lột da con mèo để nói chuyện?
dreza

1
Sự khác biệt là nếu bạn thực hiện IContextProvidermở rộng IEventContextFactory, thì việc ContextProviderthực hiện cũng sẽ cần phải thực hiện phương pháp đó. Nếu bạn thêm nó như một tài sản, bạn đang nói rằng ContextProvidercó một IEventContextFactorynhưng thực sự không biết chi tiết thực hiện.
Trevor Pilley

4

Vâng, thật tốt khi mở rộng một giao diện từ một giao diện khác.

Câu hỏi liệu đó có phải là điều đúng đắn trong một trường hợp cụ thể hay không phụ thuộc vào việc liệu có mối quan hệ "thực sự" giữa hai người hay không.

Những gì cần thiết cho một mối quan hệ "là-một" hợp lệ?

Đầu tiên, phải có sự khác biệt thực sự giữa hai giao diện, nghĩa là phải có các trường hợp thực hiện giao diện cha mẹ chứ không phải giao diện con. Nếu không có và sẽ không bao giờ có trường hợp không thực hiện cả hai giao diện, thì hai giao diện thay vào đó sẽ được hợp nhất.

Thứ hai, đó phải là trường hợp mà mọi phiên bản của giao diện con nhất thiết phải là một thể hiện của cha mẹ: không có logic (hợp lý) mà theo đó bạn sẽ tạo một thể hiện của giao diện con không có nghĩa như là một thể hiện của giao diện cha.

Nếu cả hai đều đúng, thì kế thừa là mối quan hệ đúng cho hai giao diện.


Tôi nghĩ rằng có các lớp chỉ sử dụng giao diện cơ sở và không phải là lớp dẫn xuất là không cần thiết. Ví dụ, giao diện IReadOnlyListcó thể hữu ích, ngay cả khi tất cả các lớp danh sách của tôi triển khai IList(có nguồn gốc từ IReadOnlyList).
Svick

1

Nếu một giao diện luôn muốn yêu cầu / cung cấp giao diện khác, thì hãy tiếp tục. Tôi đã thấy điều này trong một vài trường hợp IDisposiblecó ý nghĩa. Tuy nhiên, nói chung, bạn nên đảm bảo rằng ít nhất một trong các giao diện hoạt động giống như một đặc điểm hơn là trách nhiệm.

Ví dụ của bạn, nó không rõ ràng. Nếu cả hai luôn ở bên nhau, chỉ cần tạo một giao diện. Nếu người ta luôn cần người khác, tôi sẽ lo lắng về loại thừa kế "X và 1" thường dẫn đến nhiều trách nhiệm và / hoặc các vấn đề trừu tượng bị rò rỉ khác.


Cảm ơn vì điều đó. Bạn có ý nghĩa gì khi cư xử giống như một đặc điểm hơn là một trách nhiệm?
dreza

@dreza Ý tôi là trách nhiệm như trong SRP trong RẮN, và đặc điểm giống như những đặc điểm của Scala. Chủ yếu là khái niệm về cách giao diện mô hình hóa vấn đề của bạn. Liệu nó đại diện cho một phần chính của vấn đề hoặc một cái nhìn thành một phần chung của các loại khác nhau?
Telastyn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.