Có phải thói quen xấu không sử dụng giao diện? [đóng cửa]


40

Tôi hiếm khi sử dụng giao diện và thấy chúng phổ biến trong mã khác.

Ngoài ra tôi tạo các lớp con và siêu lớp (trong khi tạo các lớp của riêng tôi) hiếm khi trong mã của tôi.

  • Nó có phải là điều xấu không?
  • Bạn có đề nghị thay đổi phong cách này?
  • Liệu phong cách này có bất kỳ tác dụng phụ?
  • Đây có phải là vì tôi đã không làm việc trên bất kỳ dự án lớn?

10
Ngôn ngữ này là gì?

2
Ngoài ngôn ngữ gì, mô hình này là gì?
Armando

1
Không phải khái niệm về một "giao diện" siêu ngôn ngữ? Java có loại Giao diện tích hợp, nhưng các nhà phát triển C ++ cũng thường tạo giao diện (tiền tố chúng với I) và tất cả chúng đều phục vụ cùng một mục đích.
Ricket

4
@Ricket: Không, không hẳn. Vấn đề là C ++ cung cấp nhiều kế thừa lớp. Trong C ++, một "giao diện" mang tính khái niệm hơn nhiều và trong thực tế, chúng tôi chủ yếu sử dụng những gì họ sẽ định nghĩa là một lớp cơ sở trừu tượng. #
DeadMG

2
@Ricket không, đặc biệt nếu bạn đang làm việc trong một ngôn ngữ chức năng chứ không phải là một thủ tục hoặc OOP.
thay thế

Câu trả lời:


36

Có một số lý do tại sao bạn có thể muốn sử dụng giao diện:

  1. Các giao diện phù hợp với các tình huống trong đó các ứng dụng của bạn yêu cầu nhiều loại đối tượng có thể không liên quan để cung cấp chức năng nhất định.
  2. Các giao diện linh hoạt hơn các lớp cơ sở vì bạn có thể định nghĩa một triển khai duy nhất có thể thực hiện nhiều giao diện.
  3. Các giao diện tốt hơn trong các tình huống mà bạn không cần kế thừa triển khai từ lớp cơ sở.
  4. Các giao diện rất hữu ích trong trường hợp bạn không thể sử dụng kế thừa lớp. Ví dụ, các cấu trúc không thể kế thừa từ các lớp, nhưng chúng có thể thực hiện các giao diện.

http://msdn.microsoft.com/en-us/l Library / 3b5b8ezk (v = vs.80) .aspx

Giao diện giống như bất cứ điều gì khác trong lập trình. Nếu bạn không cần chúng, đừng sử dụng chúng. Tôi đã thấy chúng được sử dụng rộng rãi như một vấn đề về phong cách, nhưng nếu bạn không cần các thuộc tính và khả năng đặc biệt mà giao diện cung cấp, tôi không thấy lợi ích của việc sử dụng chúng "chỉ vì".


13
Ngôn ngữ của anh ấy không được chỉ định và ngôn ngữ của bạn quá cụ thể - ví dụ, trong C ++, một cấu trúc thực sự có thể kế thừa từ một lớp và bạn có thể nhân kế thừa các cơ sở không trừu tượng.
DeadMG

2
Câu trả lời này có vẻ là C # nhưng cũng liên quan đến Java nếu bạn lấy ra số 4 và chỉ áp dụng cho C ++ vì tất nhiên nhiều quyền thừa kế được cho phép trong C ++.
Ricket

2
Ngoài ra, tôi không đồng ý với tuyên bố cuối cùng. Tôi nghĩ rằng có rất nhiều thực hành tốt mà các lập trình viên nên làm nhưng đừng vì họ cảm thấy họ không cần chúng. Tôi nghĩ rằng người hỏi rất khôn ngoan khi nhìn xung quanh, thấy mọi người khác làm việc này và nghĩ có lẽ anh ta cũng nên làm điều đó nhưng trước tiên hãy hỏi "tại sao".
Ricket

3
@Ricket: Tại sao trong bốn câu trả lời của tôi. Nếu không có lý do nào được áp dụng, thì bạn không cần giao diện.
Robert Harvey

17

Cả hai kế thừa lớp và giao diện đều có vị trí của chúng. Kế thừa có nghĩa là "là một" trong khi một giao diện cung cấp một hợp đồng xác định cái gì đó "hành xử như thế nào".

Tôi muốn nói rằng sử dụng giao diện thường xuyên hơn không phải là một thực hành tồi. Tôi hiện đang đọc "C # hiệu quả - 50 cách cụ thể để cải thiện C # của bạn" của Bill Wagner. Mục số 22 nêu rõ và tôi trích dẫn: "Ưu tiên xác định và triển khai các giao diện để kế thừa".

Nói chung tôi sử dụng các lớp cơ sở khi tôi cần xác định một triển khai cụ thể của hành vi chung giữa các loại liên quan đến khái niệm. Tôi thường xuyên sử dụng giao diện hơn. Trên thực tế, tôi thường bắt đầu bằng cách xác định giao diện cho một lớp khi tôi bắt đầu tạo giao diện ... ngay cả khi cuối cùng tôi không biên dịch giao diện, tôi thấy rằng nó giúp bắt đầu bằng cách xác định API công khai của Lớp học từ đi. Nếu tôi thấy rằng tôi có nhiều lớp thực hiện giao diện và logic triển khai là giống hệt nhau, chỉ khi đó tôi mới tự hỏi liệu có nên thực hiện một lớp cơ sở chung giữa các loại hay không.

Một vài trích dẫn từ cuốn sách Bill Wagners ...

tất cả các lớp dẫn xuất ngay lập tức kết hợp hành vi đó. Việc thêm một thành viên vào một giao diện sẽ phá vỡ tất cả các lớp thực hiện giao diện đó. Chúng sẽ không chứa phương thức mới và sẽ không còn biên dịch nữa. Mỗi người triển khai phải cập nhật loại đó để bao gồm thành viên mới. Lựa chọn giữa một lớp cơ sở trừu tượng và một giao diện là một câu hỏi về cách tốt nhất để hỗ trợ sự trừu tượng của bạn theo thời gian. Các giao diện được cố định: Bạn phát hành một giao diện dưới dạng hợp đồng cho một bộ chức năng mà bất kỳ loại nào cũng có thể thực hiện. Các lớp cơ sở có thể được mở rộng theo thời gian. Những phần mở rộng đó trở thành một phần của mọi lớp dẫn xuất. Hai mô hình có thể được trộn lẫn để sử dụng lại mã thực thi trong khi hỗ trợ nhiều giao diện. " Chúng sẽ không chứa phương thức mới và sẽ không còn biên dịch nữa. Mỗi người triển khai phải cập nhật loại đó để bao gồm thành viên mới. Lựa chọn giữa một lớp cơ sở trừu tượng và một giao diện là một câu hỏi về cách tốt nhất để hỗ trợ sự trừu tượng của bạn theo thời gian. Các giao diện được cố định: Bạn phát hành một giao diện dưới dạng hợp đồng cho một bộ chức năng mà bất kỳ loại nào cũng có thể thực hiện. Các lớp cơ sở có thể được mở rộng theo thời gian. Những phần mở rộng đó trở thành một phần của mọi lớp dẫn xuất. Hai mô hình có thể được trộn lẫn để sử dụng lại mã thực thi trong khi hỗ trợ nhiều giao diện. " Chúng sẽ không chứa phương thức mới và sẽ không còn biên dịch nữa. Mỗi người triển khai phải cập nhật loại đó để bao gồm thành viên mới. Lựa chọn giữa một lớp cơ sở trừu tượng và một giao diện là một câu hỏi về cách tốt nhất để hỗ trợ sự trừu tượng của bạn theo thời gian. Các giao diện được cố định: Bạn phát hành một giao diện dưới dạng hợp đồng cho một bộ chức năng mà bất kỳ loại nào cũng có thể thực hiện. Các lớp cơ sở có thể được mở rộng theo thời gian. Những phần mở rộng đó trở thành một phần của mọi lớp dẫn xuất. Hai mô hình có thể được trộn lẫn để sử dụng lại mã thực thi trong khi hỗ trợ nhiều giao diện. " Bạn phát hành một giao diện dưới dạng hợp đồng cho một bộ chức năng mà bất kỳ loại nào cũng có thể thực hiện. Các lớp cơ sở có thể được mở rộng theo thời gian. Những phần mở rộng đó trở thành một phần của mọi lớp dẫn xuất. Hai mô hình có thể được trộn lẫn để sử dụng lại mã thực thi trong khi hỗ trợ nhiều giao diện. " Bạn phát hành một giao diện dưới dạng hợp đồng cho một bộ chức năng mà bất kỳ loại nào cũng có thể thực hiện. Các lớp cơ sở có thể được mở rộng theo thời gian. Những phần mở rộng đó trở thành một phần của mọi lớp dẫn xuất. Hai mô hình có thể được trộn lẫn để sử dụng lại mã thực thi trong khi hỗ trợ nhiều giao diện. "

"Giao diện mã hóa cung cấp tính linh hoạt cao hơn cho các nhà phát triển khác so với mã hóa cho các loại lớp cơ sở."

"Sử dụng các giao diện để xác định API cho một lớp cung cấp tính linh hoạt cao hơn."

"Khi kiểu của bạn hiển thị các thuộc tính dưới dạng các lớp, nó sẽ hiển thị toàn bộ giao diện cho lớp đó. Sử dụng các giao diện, bạn có thể chọn chỉ hiển thị các phương thức và thuộc tính bạn muốn khách hàng sử dụng."

"Các lớp cơ sở mô tả và thực hiện các hành vi phổ biến trên các loại bê tông liên quan. Các giao diện mô tả các phần chức năng nguyên tử mà các loại bê tông không liên quan có thể thực hiện. Cả hai đều có vị trí của chúng. Các lớp xác định các loại bạn tạo. Các giao diện mô tả hành vi của các loại đó là các phần chức năng. Nếu bạn hiểu được sự khác biệt, bạn sẽ tạo ra các thiết kế biểu cảm hơn, linh hoạt hơn khi đối mặt với sự thay đổi. Sử dụng hệ thống phân cấp lớp để xác định các loại liên quan.


2
Vâng, tôi đọc nó và nghĩ rằng đó là một câu trả lời tốt.
Eric King

1
@ mc10 Không chắc vấn đề là gì. Anh ấy đã tham khảo một cuốn sách và nửa câu trả lời của anh ấy chỉ là những trích dẫn từ cuốn sách mà anh ấy rõ ràng cho bạn biết trong trường hợp bạn không muốn lãng phí thời gian của mình.
Pete

@Pete Tôi không nói rằng câu trả lời là xấu, nhưng chỉ là nó hơi dài. Tôi nghi ngờ rằng đôi khi bạn cần toàn bộ trích dẫn.
kevinji

3
haha, nếu đây là tl; dr, tôi không chắc bạn sẽ thích toàn bộ câu trả lời chất lượng cao StackExchange này.
Nic

haha, cảm ơn các bạn Vâng, điều đó đã xảy ra với tôi rằng câu trả lời hơi dài dòng, nhưng tôi nghĩ rằng tôi sẽ đủ điều kiện trả lời bằng cách bao gồm các trích dẫn có liên quan từ ông Wagner, giải thích về những lợi thế và bất lợi của giao diện so với kế thừa, cũng như các tình huống mỗi cái thích hợp hơn Có lẽ trích dẫn cuốn sách trực tiếp không thêm nhiều giá trị cho câu trả lời của tôi.
John Connelly

8

Một điều chưa được đề cập là thử nghiệm: trong tất cả các thư viện mô phỏng C #, cũng như một số cho Java, các lớp không thể bị chế giễu trừ khi chúng thực hiện giao diện. Điều này dẫn đến nhiều dự án theo các thực tiễn Agile / TDD để cung cấp cho mỗi lớp giao diện riêng.

Một số người coi đây là cách thực hành tốt nhất, bởi vì nó "làm giảm sự ghép đôi", nhưng tôi không đồng ý - tôi nghĩ đó chỉ là một cách giải quyết cho sự thiếu hụt trong ngôn ngữ.


Tôi nghĩ các giao diện được sử dụng tốt nhất khi bạn có hai hoặc nhiều lớp, theo cách trừu tượng, thực hiện "cùng một thứ", nhưng theo những cách khác nhau.

Chẳng hạn, khung .Net có nhiều lớp lưu trữ danh sách các thứ , nhưng tất cả chúng đều lưu trữ các thứ đó theo những cách khác nhau. Vì vậy, nó có ý nghĩa để có một IList<T>giao diện trừu tượng , có thể được thực hiện bằng các phương pháp khác nhau.

Bạn cũng nên sử dụng nó khi bạn muốn 2+ lớp có thể hoán đổi cho nhau hoặc có thể thay thế trong tương lai. Nếu một cách lưu trữ danh sách mới xuất hiện trong tương lai, AwesomeList<T>thì giả sử bạn đã sử dụng IList<T>toàn bộ mã của mình, thay đổi nó thành sử dụng AwesomeList<T>có nghĩa là chỉ thay đổi vài chục dòng, thay vì vài trăm / nghìn.


5

Kết quả chính của việc không sử dụng tính kế thừa và giao diện khi chúng phù hợp là khớp nối chặt chẽ . Điều này có thể hơi khó học để nhận ra, nhưng thông thường, triệu chứng rõ ràng nhất là khi bạn thực hiện thay đổi, bạn thấy bạn thường xuyên phải trải qua một loạt các tệp khác để thực hiện thay đổi trong hiệu ứng gợn.


4

Không, điều này không tệ chút nào. Các giao diện rõ ràng nên được sử dụng, nếu và chỉ khi, hai lớp có giao diện chung cần được hoán đổi cho nhau trong thời gian chạy. Nếu chúng không cần phải thay thế cho nhau, thì chúng không được thừa kế. Nó đơn giản như vậy. Kế thừa là mong manh và nên tránh bất cứ nơi nào có thể. Nếu bạn có thể tránh nó hoặc sử dụng thuốc generic thay thế, thì hãy làm.

Vấn đề là, trong các ngôn ngữ như C # và Java với tính tổng quát về thời gian biên dịch yếu, bạn có thể vi phạm DRY vì không có cách nào để viết một phương thức có thể xử lý nhiều hơn một lớp trừ khi tất cả các lớp kế thừa từ cùng một cơ sở. C # 4 dynamic có thể đối phó với điều này, mặc dù.

Vấn đề là, tính kế thừa giống như các biến toàn cục - một khi bạn thêm nó và mã của bạn phụ thuộc vào nó, Chúa sẽ giúp bạn lấy nó đi. Tuy nhiên, bạn có thể thêm nó bất cứ lúc nào và thậm chí bạn có thể thêm nó mà không thay đổi lớp cơ sở bằng cách sử dụng trình bao bọc các loại.


1
Lý do cho downvote?
DeadMG

Không chắc chắn, có một upvote. Đó là một câu trả lời tốt.
Bryan Boettcher

3

Có, không (hoặc quá hiếm khi) sử dụng giao diện có lẽ là một điều xấu. Các giao diện (theo nghĩa trừu tượng và cấu trúc ngôn ngữ C # / Java là một xấp xỉ khá tốt của ý nghĩa trừu tượng đó) xác định các điểm tương tác rõ ràng giữa các hệ thống và các hệ thống con. Điều này giúp giảm khớp nối và làm cho hệ thống dễ bảo trì hơn. Như với bất cứ điều gì cải thiện khả năng bảo trì, nó trở nên quan trọng hơn khi hệ thống càng lớn.


3

Tôi đã không sử dụng một giao diện trong nhiều năm. Tất nhiên điều này là do tôi đã lập trình gần như độc quyền tại Erlang trong nhiều năm và toàn bộ khái niệm về giao diện đơn giản là không tồn tại. (Gần nhất bạn nhận được là một "hành vi" và đó không thực sự giống như vậy trừ khi bạn nheo mắt thực sự khó khăn nhìn chúng ra khỏi khóe mắt.)

Vì vậy, thực sự, câu hỏi của bạn phụ thuộc vào mô hình (OOP trong trường hợp này) và hơn nữa, thực sự khá phụ thuộc vào ngôn ngữ (có ngôn ngữ OOP không có giao diện).


2

Nếu bạn đang nói về việc sử dụng Java, một lý do để sử dụng các giao diện là chúng cho phép sử dụng các đối tượng proxy mà không cần các thư viện tạo mã. Đây có thể là một lợi thế đáng kể khi bạn đang làm việc với một khung phức tạp như Spring. Hơn nữa, một số chức năng yêu cầu giao diện: RMI là ví dụ kinh điển về điều này, vì bạn phải mô tả chức năng bạn đang cung cấp về mặt giao diện (kế thừa từ đó java.rmi.Remote) tuy nhiên bạn sẽ triển khai chúng.


1

Mọi thứ đang thay đổi ( MS Moles ), nhưng lý do chính mà tôi nghĩ rằng thật tốt khi mã hóa hầu như chỉ dành cho các giao diện là chúng dễ dàng giả định và phù hợp tự nhiên với kiến ​​trúc IoC.

IMO bạn chỉ nên làm việc với các giao diện hoặc DAO hoàn toàn câm lặng bất cứ nơi nào có thể. Khi bạn có được suy nghĩ này, và bạn bắt đầu sử dụng một thư viện không phơi bày thông qua các giao diện và thực hiện mọi thứ thông qua các đối tượng cụ thể mà tôi phải thành thật, tất cả đều cảm thấy hơi lộn xộn.


0

Đối với các dự án thời trang cũ, người ta sử dụng các giao diện để tránh các tham chiếu vòng tròn, bởi vì các tham chiếu vòng tròn có thể trở thành vấn đề bảo trì lớn trong thời gian dài.

Xấu:

class B; // forward declaration
class A
{
  B* b;
};

class B
{
  A* a;
}

Không tệ:

class PartOfClassB_AccessedByA
{
};

class A
{
  PartOfClassB_AccessedByA* b;
};

class B : public PartOfClassB_AccessedByA
{
  A* a;
}

Thông thường A, B, PartOfClassB_AccessedByA được triển khai với các tệp riêng biệt.


0

Lập trình dựa trên giao diện giúp làm cho mã linh hoạt hơn và dễ kiểm tra hơn. Các lớp thực hiện có thể được thay đổi mà không cần chạm vào mã máy khách [Linh hoạt]. Trong khi kiểm tra mã, người ta có thể thay thế lập trình dựa trên oInterface thực tế giúp làm cho mã linh hoạt hơn và dễ kiểm tra hơn. Các lớp thực hiện có thể được thay đổi mà không cần chạm vào mã máy khách [Linh hoạt]. Trong khi kiểm tra mã, người ta có thể thay thế đối tượng thực tế bằng các đối tượng giả [Khả năng kiểm tra] .bject bằng các đối tượng giả [Khả năng kiểm tra].

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.