Tại sao các giao diện hữu ích?


158

Tôi đã học và viết mã bằng C # một thời gian rồi. Nhưng tôi vẫn không thể nhận ra sự hữu ích của Giao diện. Họ mang quá ít đến bàn. Ngoài việc cung cấp chữ ký của chức năng, họ không làm gì cả. Nếu tôi có thể nhớ tên và chữ ký của các chức năng cần được thực hiện, thì không cần chúng. Họ ở đó chỉ để đảm bảo rằng các chức năng đã nói (trong giao diện) được triển khai trong lớp kế thừa.

C # là một ngôn ngữ tuyệt vời, nhưng đôi khi nó mang lại cho bạn cảm giác rằng lần đầu tiên Microsoft tạo ra vấn đề (không cho phép nhiều kế thừa) và sau đó cung cấp giải pháp, một cách khá tẻ nhạt.

Đó là sự hiểu biết của tôi dựa trên kinh nghiệm mã hóa hạn chế. Bạn lấy gì trên giao diện? Tần suất bạn sử dụng chúng và điều gì khiến bạn làm như vậy?


55
"Nếu tôi có thể nhớ tên và chữ ký của các chức năng cần được thực hiện, thì không cần chúng." Tuyên bố này khiến tôi nghi ngờ bạn nên xem xét thêm một chút về lợi thế của các ngôn ngữ gõ tĩnh .
Steven Jeuris

37
Quên C #, quên Java, quên ngôn ngữ. Nó chỉ đơn giản là suy nghĩ về OO. Tôi sẽ khuyến khích bạn chọn một số tài liệu đọc từ những người như Robert C. Martin, Martin Fowler, Michael Feathers, Gang of Four, v.v., vì nó sẽ giúp mở rộng suy nghĩ của bạn.
Anthony Pegram

27
Tôi đã mất hơn hai năm để thực sự hiểu giao diện nào tốt cho. Đề nghị của tôi: nghiên cứu các mẫu thiết kế. Vì hầu hết chúng đều dựa vào giao diện, bạn sẽ nhanh chóng hiểu tại sao chúng lại hữu ích như vậy.
Oliver Weiler

37
Bạn đã có rất nhiều để tìm hiểu bạn bè.
ChaosPandion

60
@ChaosPandion tất cả chúng ta đều có rất nhiều điều để học hỏi
kenwarner

Câu trả lời:


151

Họ ở đó chỉ để đảm bảo rằng các chức năng đã nói (trong giao diện) được triển khai trong lớp kế thừa.

Chính xác. Đó là một lợi ích đủ tuyệt vời để biện minh cho tính năng này. Như những người khác đã nói, một giao diện là một nghĩa vụ theo hợp đồng để thực hiện các phương thức, tính chất và sự kiện nhất định. Lợi ích hấp dẫn của ngôn ngữ gõ tĩnh là trình biên dịch có thể xác minh rằng một hợp đồng mà mã của bạn dựa trên thực sự được đáp ứng.

Điều đó nói rằng, giao diện là một cách khá yếu để thể hiện nghĩa vụ hợp đồng. Nếu bạn muốn một cách mạnh mẽ và linh hoạt hơn để thể hiện nghĩa vụ theo hợp đồng, hãy xem xét tính năng Hợp đồng mã được cung cấp với phiên bản cuối cùng của Visual Studio.

C # là một ngôn ngữ tuyệt vời, nhưng đôi khi nó mang lại cho bạn cảm giác rằng đầu tiên Microsoft tạo ra vấn đề (không cho phép nhiều kế thừa) và sau đó cung cấp giải pháp, một cách khá tẻ nhạt.

Vâng, tôi rất vui vì bạn thích nó.

Tất cả các thiết kế phần mềm phức tạp là kết quả của việc cân nhắc các tính năng xung đột với nhau và cố gắng tìm ra "điểm ngọt" mang lại lợi ích lớn cho chi phí nhỏ. Chúng tôi đã học được qua kinh nghiệm đau đớn rằng các ngôn ngữ cho phép nhiều kế thừa cho mục đích chia sẻ triển khai có lợi ích tương đối nhỏ và chi phí tương đối lớn. Cho phép nhiều kế thừa chỉ trên các giao diện, không chia sẻ chi tiết triển khai, mang lại nhiều lợi ích của nhiều kế thừa mà không cần hầu hết các chi phí.


Tôi chỉ đọc "Microsoft tạo ra vấn đề bằng cách không cho phép thừa kế nhiều lần" và tôi nghĩ Eric Lippert sẽ có điều gì đó để nói về điều đó.
cấu hình

Liên quan nhiều hơn đến câu trả lời này: Eric, bạn đang đề cập đến người hỏi về Hợp đồng mã, nhưng chúng chưa hoàn thiện; bất cứ điều gì khác ngoài các hợp đồng cơ bản nhất đều không được thực thi bởi trình kiểm tra tĩnh. Tôi đã thử sử dụng Hợp đồng mã trên một dự án nhỏ; Tôi đã thêm hàng trăm dòng cho mỗi và mọi phương thức chỉ định mọi thứ tôi có thể về đầu vào và đầu ra, tuy nhiên, tôi đã phải thêm rất nhiều Assumecuộc gọi, cho các trường hợp như thành viên mảng hoặc liệt kê. Sau khi thêm mọi thứ và thấy mớ hỗn độn được xác minh tĩnh mà tôi có, tôi đã hoàn nguyên trong kiểm soát nguồn vì nó làm giảm chất lượng dự án của tôi.
cấu hình

17
@configurator: Chúng không đầy đủ vì chúng không thể hoàn thành; xác minh chương trình tĩnh với các hợp đồng tùy ý tương đương với việc giải quyết vấn đề tạm dừng. (Ví dụ: bạn có thể viết hợp đồng mã nói rằng các đối số cho một phương thức phải là một ví dụ mẫu cho Định lý cuối cùng của Fermat; nhưng trình xác minh tĩnh sẽ không thể xác minh rằng không có đối số nào như vậy.) phải sử dụng nó một cách thận trọng nếu bạn mong muốn trình xác minh tĩnh hoàn thành công việc của nó trước cái chết nhiệt của vũ trụ. (Nếu khiếu nại của bạn là BCL không được chú thích đầy đủ: Tôi đồng ý.)
Eric Lippert

2
Tôi hy vọng nó nhận ra rằng khi một phương thức hứa hẹn rằng mảng kết quả hoặc phép liệt kê không chứa null, phương thức sử dụng có thể sử dụng các giá trị ở những nơi không cho phép null. Đó là điều tôi mong đợi nó sẽ làm điều đó, và nó quá quan trọng để có thể sử dụng mà không có nó; bất cứ điều gì khác chỉ là một phần thưởng. Điều đó nói rằng, tôi biết xác minh tĩnh không thể hoàn tất, đó là lý do tại sao tôi nghĩ rằng nó không phải là một lựa chọn tốt để dựa vào các hợp đồng.
cấu hình

9
+1 cho "Vâng, tôi rất vui vì bạn thích nó." Và tất cả những thứ khác nữa.
Robert S.

235

nhập mô tả hình ảnh ở đây

Vì vậy, trong ví dụ này, PowerSocket không biết gì về các đối tượng khác. Tất cả các đối tượng đều phụ thuộc vào Power do PowerSocket cung cấp, do đó chúng triển khai IPowerPlug và để chúng có thể kết nối với nó.

Các giao diện rất hữu ích vì chúng cung cấp các hợp đồng mà các đối tượng có thể sử dụng để làm việc cùng nhau mà không cần biết bất cứ điều gì khác về nhau.


4
Đối tượng phía dưới bên trái không giống như nó thực hiện IPowerPlug =)
Steven Striga

100
Chết tiệt, nhưng chúng ta sẽ phải sử dụng mẫu Adaptor để sử dụng IPowerPlug ở các quốc gia khác nhau!
Steven Jeuris

Jerry gian lận một thiết bị để làm việc xung quanh giao diện là không an toàn (nhưng một số người vẫn làm điều đó thường trích dẫn hiệu suất như một lý do chưa được kiểm tra) và có khả năng dẫn đến hỏa hoạn.
YoungJohn

4
Câu trả lời này thật tuyệt vời ...
Mario Garcia

Chỉ đưa ra câu trả lời này không nói - trong ví dụ cụ thể này - tại sao sử dụng giao diện sẽ thích hợp hơn kế thừa. Một người mới sử dụng giao diện có thể hỏi tại sao tất cả họ không chỉ thừa kế từ ví dụ MainsPoweredDevice cung cấp tất cả chức năng cắm, với ổ cắm chấp nhận mọi thứ có nguồn gốc từ MainsPoweredDevice.
thành

145

Ngoài việc cung cấp chữ ký của chức năng, họ không làm gì cả. Nếu tôi có thể nhớ tên và chữ ký của các chức năng cần được thực hiện, thì không cần chúng

Quan điểm của các giao diện không phải là để giúp bạn nhớ phương pháp nào cần thực hiện, nó ở đây để xác định hợp đồng . Trong ví dụ về foreach P.Brian.Mackey ( hóa ra là sai , nhưng chúng tôi không quan tâm), IEnumerable định nghĩa một hợp đồng giữa foreachbất kỳ điều gì có thể đếm được. Nó nói: "Dù bạn là ai, miễn là bạn tuân thủ hợp đồng (thực hiện IEnumerable), tôi hứa với bạn tôi sẽ lặp lại tất cả các yếu tố của bạn". Và, đó là tuyệt vời (đối với một ngôn ngữ không năng động).

Nhờ các giao diện, bạn có thể đạt được khớp nối rất thấp giữa hai lớp.



Tôi không thích sử dụng thuật ngữ "gõ vịt" bởi vì nó có nghĩa là những thứ khác nhau cho những người khác nhau. Chúng tôi sử dụng khớp mẫu cho vòng lặp "foreach" bởi vì khi nó được thiết kế, IEnumerable <T> không khả dụng. Chúng tôi sử dụng khớp mẫu cho LINQ vì hệ thống loại C # quá yếu để có thể nắm bắt được "mẫu đơn nguyên" mà chúng tôi cần; bạn sẽ cần một cái gì đó giống như hệ thống loại Haskell.
Eric Lippert

@Eric: Không "khớp mẫu" có cùng một vấn đề không? Khi tôi nghe nó, tôi nghĩ F # / Scala / Haskell. Nhưng tôi đoán đó là một ý tưởng rộng hơn so với gõ vịt.
Daniel

@Daniel: Vâng, tôi cho là có. Tôi đoán là sáu trong số một nửa tá thứ khác!
Eric Lippert

36

Giao diện là cách tốt nhất để duy trì các cấu trúc tách rời tốt.

Khi viết bài kiểm tra, bạn sẽ thấy rằng các lớp cụ thể sẽ không hoạt động trong môi trường kiểm tra của bạn.

Ví dụ: Bạn muốn kiểm tra một lớp phụ thuộc vào lớp Dịch vụ truy cập dữ liệu . Nếu lớp đó đang nói chuyện với một dịch vụ web hoặc cơ sở dữ liệu - bài kiểm tra đơn vị của bạn sẽ không chạy trong môi trường kiểm tra của bạn (cộng với việc nó đã biến thành kiểm tra tích hợp).

Giải pháp? Sử dụng Giao diện cho Dịch vụ truy cập dữ liệu của bạn và mô phỏng giao diện đó để bạn có thể kiểm tra lớp của mình dưới dạng một đơn vị.

Mặt khác, WPF & Silverlight hoàn toàn không chơi với Giao diện khi có ràng buộc. Đây là một nếp nhăn khá khó chịu.


2
nghe nghe Các giao diện được phát minh để giải quyết các vấn đề khác, chẳng hạn như đa hình. Tuy nhiên, đối với tôi, chúng trở thành của riêng chúng khi thực hiện mô hình Tiêm phụ thuộc.
andy

29

Giao diện là xương sống của đa hình (tĩnh)! Giao diện là những gì quan trọng. Kế thừa sẽ không hoạt động nếu không có giao diện, vì các lớp con về cơ bản kế thừa giao diện đã được triển khai của cha mẹ.

Bạn có thường xuyên sử dụng chúng và điều gì khiến bạn làm như vậy ??

Khá thường xuyên. Tất cả mọi thứ cần phải cắm là một giao diện trong các ứng dụng của tôi. Thường thì bạn có các lớp không liên quan khác cần cung cấp hành vi tương tự. Bạn không thể giải quyết các vấn đề như vậy với thừa kế.

Cần các thuật toán khác nhau để thực hiện các hoạt động trên cùng một dữ liệu? Sử dụng một giao diện ( xem mẫu chiến lược )!

Bạn có muốn sử dụng các triển khai danh sách khác nhau? Mã đối với một giao diện và người gọi không cần phải lo lắng về việc thực hiện!

Nó được coi là một cách thực hành tốt (không chỉ trong OOP) để mã hóa các giao diện theo lứa tuổi, vì một lý do duy nhất: Thật dễ dàng để thay đổi cách triển khai khi bạn nhận ra nó không phù hợp với nhu cầu của bạn. Sẽ khá cồng kềnh nếu bạn cố gắng đạt được điều đó chỉ với nhiều kế thừa hoặc nó tập trung vào việc tạo các lớp trống để cung cấp giao diện cần thiết.


1
Chưa bao giờ nghe nói về đa hình, ý bạn là đa hình?
Steven Jeuris

1
điều đó đang được nói, nếu microsoft cho phép nhiều kế thừa ở vị trí đầu tiên, sẽ không có lý do gì để tồn tại các giao diện
Pankaj Upadhyay

10
@Pankaj Upadhyay: Nhiều kế thừa và giao diện là hai đôi giày khác nhau. Điều gì nếu bạn cần một giao diện của hai lớp không liên quan với hành vi khác nhau? Bạn không thể giải quyết điều đó bằng nhiều kế thừa. Bạn phải thực hiện nó một cách riêng biệt nào. Và sau đó bạn sẽ cần một cái gì đó để mô tả giao diện để cung cấp hành vi đa hình. Nhiều gia tài là một con hẻm mù để đi bộ trong nhiều trường hợp, và quá dễ để tự bắn vào chân mình sớm hay muộn.
Falcon

1
Hãy đơn giản hóa. Nếu giao diện của tôi thực hiện hai chức năng Hiển thị và Nhận xét và tôi có một lớp thực hiện chúng. Vậy thì tại sao tôi không gỡ bỏ giao diện và sử dụng các chức năng trực tiếp. Điều tôi đang nói là họ chỉ đơn thuần cung cấp cho bạn tên của các chức năng cần thiết để thực hiện. Nếu ai đó có thể nhớ các chức năng đó thì tại sao lại tạo giao diện
Pankaj Upadhyay

9
@Pankaj, nếu đó là tất cả những gì bạn cần giao diện, thì đừng sử dụng nó. YOu sử dụng một giao diện khi bạn có một chương trình muốn không biết gì về mọi khía cạnh của lớp và truy cập nó theo Loại cơ sở của nó, tức là giao diện. Họ không cần biết bất kỳ lớp con nào, chỉ là nó thuộc loại giao diện. Như vậy, sau đó bạn có thể gọi phương thức đã triển khai của lớp con thông qua tham chiếu đến giao diện của đối tượng. Đây là kế thừa cơ bản và công cụ thiết kế. Không có nó, bạn cũng có thể sử dụng C. Ngay cả khi bạn không sử dụng nó một cách rõ ràng, khung sẽ không hoạt động nếu không có nó.
Jonathan Henson

12

Bạn có thể đã sử dụng foreachvà thấy nó là một công cụ lặp khá hữu ích. Bạn có biết rằng nó yêu cầu một giao diện để hoạt động, IEnumerable ?

Đó chắc chắn là một trường hợp cụ thể nói lên tính hữu ích của một giao diện.


5
Trên thực tế, foreach không yêu cầu IEnumerable: msdn.microsoft.com/en-us/l Library / 9yb8xew9% 28VS.80% 29.aspx
Matt H

1
Tôi đã nghiên cứu tất cả những điều đó nhưng nó giống như giữ tai bằng tay khác. Nếu nhiều kế thừa được cho phép, giao diện sẽ là một lựa chọn xa.
Pankaj Upadhyay

2
Giao diện là nhiều kế thừa, một cái gì đó thường bị lãng quên. Tuy nhiên, họ không cho phép nhiều kế thừa hành vi và trạng thái. Mixins hoặc đặc điểm cho phép nhiều sự kế thừa hành vi, nhưng không chia sẻ trạng thái gây ra sự cố: en.wikipedia.org/wiki/Mixin
Matt H

@Pankaj, không chính thức, nhưng bạn có phiền nếu tôi hỏi ngôn ngữ mẹ đẻ của bạn là gì không? "Giữ tai bằng tay kia" là một thành ngữ tuyệt vời và tôi đã tò mò nó đến từ đâu.
Kevin

3
@Iceman. LOL .... Tôi đến từ Ấn Độ. Và đây là một thành ngữ phổ biến phản ánh việc làm những điều dễ dàng theo cách khó khăn.
Pankaj Upadhyay

11

Các giao diện là để mã hóa các đối tượng như phích cắm là hệ thống dây điện trong gia đình. Bạn sẽ hàn đài phát thanh của bạn trực tiếp đến hệ thống dây điện trong nhà của bạn? Làm thế nào về máy hút bụi của bạn? Dĩ nhiên là không. Phích cắm và ổ cắm mà nó lắp vào, tạo thành "giao diện" giữa hệ thống dây điện trong nhà của bạn và thiết bị cần nguồn điện từ nó. Hệ thống dây điện trong nhà của bạn không cần biết gì về thiết bị ngoài việc nó sử dụng phích cắm nối đất ba chấu và yêu cầu năng lượng điện ở 120VAC <= 15A. Ngược lại, thiết bị không đòi hỏi kiến ​​thức phức tạp về cách ngôi nhà của bạn có dây, ngoài ra nó có một hoặc nhiều ổ cắm ba chấu được đặt ở vị trí thuận tiện cung cấp 120VAC <= 15A.

Các giao diện thực hiện một chức năng rất giống nhau trong mã. Một đối tượng có thể khai báo rằng một biến, tham số hoặc kiểu trả về cụ thể thuộc loại giao diện. Giao diện không thể được khởi tạo trực tiếp bằng một newtừ khóa, nhưng đối tượng của tôi có thể được cung cấp hoặc tìm thấy việc triển khai giao diện mà nó sẽ cần để làm việc. Một khi đối tượng có sự phụ thuộc của nó, nó không cần phải biết chính xác sự phụ thuộc đó là gì, nó chỉ cần biết nó có thể gọi các phương thức X, Y và Z dựa trên sự phụ thuộc. Việc triển khai giao diện không cần phải biết chúng sẽ được sử dụng như thế nào, chúng chỉ cần biết rằng chúng sẽ được yêu cầu cung cấp các phương thức X, Y và Z với các chữ ký cụ thể.

Do đó, bằng cách trừu tượng hóa nhiều đối tượng đằng sau cùng một giao diện, bạn cung cấp một bộ chức năng chung cho bất kỳ người tiêu dùng đối tượng nào của giao diện đó. Bạn không cần phải biết đối tượng là, ví dụ, Danh sách, Từ điển, LinkedList, OrderedList hoặc bất cứ thứ gì. Vì bạn biết tất cả những thứ này là IEnumerables, nên bạn có thể sử dụng các phương thức của IEnumerable để đi qua từng phần tử trong các bộ sưu tập này cùng một lúc. Bạn không cần phải biết rằng một lớp đầu ra là ConsoleWriter, FileWriter, NetworkStreamWriter hoặc thậm chí là MulticastWriter có các kiểu người viết khác; tất cả những gì bạn phải biết là tất cả đều là IWriters (hoặc bất cứ điều gì) và do đó họ có phương thức "Viết" mà bạn có thể chuyển một chuỗi vào và chuỗi đó sẽ được xuất ra.


7

Mặc dù rõ ràng đây là một điều trị để lập trình viên (ít nhất là lúc đầu) có nhiều thừa kế, đây là một thiếu sót gần như không đáng kể và trong hầu hết các trường hợp, bạn không nên dựa vào nhiều kế thừa. Lý do cho điều này rất phức tạp, nhưng nếu bạn thực sự muốn tìm hiểu về nó, hãy xem xét kinh nghiệm từ hai ngôn ngữ lập trình nổi tiếng nhất (theo chỉ số TIOBE ) hỗ trợ nó: C ++ và Python (thứ 3 và thứ 8 đáng kính).

Trong Python, nhiều kế thừa được hỗ trợ, nhưng hầu như bị các lập trình viên hiểu lầm và nói rằng bạn biết nó hoạt động như thế nào, có nghĩa là đọc và hiểu bài báo này về chủ đề: Thứ tự giải quyết phương pháp . Một cái gì đó khác, xảy ra trong Python, là các giao diện sắp xếp theo ngôn ngữ - Zope.Interfaces.

Đối với C ++, google "phân cấp kim cương C ++" và nhận thấy sự xấu xí sắp che chở bạn. Ưu điểm C ++ biết cách sử dụng nhiều kế thừa. Mọi người khác thường chỉ chơi xung quanh mà không biết kết quả sẽ ra sao. Một điều nữa cho thấy sự hữu ích của các giao diện là thực tế, trong nhiều trường hợp, một lớp có thể cần ghi đè hoàn toàn hành vi của cha mẹ nó. Trong các trường hợp như vậy, việc triển khai cha mẹ là không cần thiết và chỉ làm gánh nặng lớp con với bộ nhớ cho các biến riêng của cha mẹ, điều này có thể không quan trọng trong thời đại C #, nhưng vấn đề khi bạn thực hiện lập trình nhúng. Nếu bạn sử dụng một giao diện, vấn đề đó là không tồn tại.

Tóm lại, các giao diện, theo tôi, là một phần thiết yếu của OOP, bởi vì chúng thực thi một hợp đồng. Đa kế thừa rất hữu ích trong các trường hợp hạn chế và thường chỉ dành cho những người biết sử dụng nó. Vì vậy, nếu bạn là người mới bắt đầu, bạn là người được điều trị bằng cách thiếu nhiều thừa kế - điều này mang đến cho bạn cơ hội tốt hơn để không phạm sai lầm .

Ngoài ra, trong lịch sử, ý tưởng cho một giao diện bắt nguồn sớm hơn nhiều so với thông số thiết kế C # của Microsoft. Hầu hết mọi người coi C # là một bản nâng cấp so với Java (theo hầu hết các giác quan) và đoán xem C # có giao diện từ đâu - Java. Giao thức là một từ cũ hơn cho cùng một khái niệm và nó cũ hơn .NET.

Cập nhật: Bây giờ tôi thấy tôi có thể đã trả lời một câu hỏi khác - tại sao giao diện thay vì nhiều kế thừa, nhưng đây dường như là câu trả lời bạn đang tìm kiếm. Bên cạnh một ngôn ngữ OO nên có ít nhất một trong hai ngôn ngữ và các câu trả lời khác đã bao gồm câu hỏi ban đầu của bạn.


6

Thật khó cho tôi để tưởng tượng mã C # hướng đối tượng sạch mà không sử dụng giao diện. Bạn sử dụng chúng bất cứ khi nào bạn muốn thực thi tính khả dụng của một số chức năng nhất định mà không buộc các lớp phải kế thừa từ một lớp cơ sở cụ thể và điều này cho phép mã của bạn có mức khớp nối (thấp) có liên quan.

Tôi không đồng ý rằng nhiều kế thừa tốt hơn so với việc có các giao diện, ngay cả trước khi chúng ta tranh luận rằng nhiều kế thừa đi kèm với các nỗi đau riêng của nó. Các giao diện là một công cụ cơ bản để cho phép tái sử dụng đa hình và mã, người ta cần thêm gì nữa?


5

Cá nhân tôi thích lớp trừu tượng và sử dụng nó nhiều hơn một giao diện. Sự khác biệt chính đi kèm với việc tích hợp với các giao diện .NET như IDis Dùng, IEnumerable và vv ... và với COM interop. Ngoài ra, giao diện là một nỗ lực ít hơn để viết so với một lớp trừu tượng và một lớp có thể thực hiện nhiều hơn một giao diện trong khi nó chỉ có thể kế thừa từ một lớp.

Điều đó nói rằng, tôi thấy rằng hầu hết mọi thứ tôi sẽ sử dụng một giao diện được phục vụ tốt hơn bởi một lớp trừu tượng. Các hàm ảo thuần túy - các hàm trừu tượng-- cho phép bạn buộc người triển khai xác định hàm tương tự như cách giao diện buộc người thực hiện xác định tất cả các thành viên của nó.

Tuy nhiên, bạn thường sử dụng một giao diện khi bạn không muốn áp đặt một thiết kế nhất định lên siêu hạng, trong khi bạn sẽ sử dụng một lớp trừu tượng để có một thiết kế có thể sử dụng lại được thực hiện chủ yếu.

Tôi đã sử dụng nhiều giao diện với việc viết các môi trường plugin bằng cách sử dụng không gian tên System.ComponentModel. Họ đến khá tiện dụng.


1
Rất tốt đặt! Tôi đoán bạn sẽ thích bài viết của tôi về các lớp trừu tượng. Trừu tượng là tất cả mọi thứ .
Steven Jeuris

5

Tôi có thể nói tôi liên quan đến điều đó. Khi tôi mới bắt đầu tìm hiểu về OO và C #, tôi cũng không có Giao diện. Vậy là được rồi. Chúng tôi chỉ cần đi qua một cái gì đó sẽ làm cho bạn đánh giá cao sự tiện lợi của giao diện.

Hãy để tôi thử hai cách tiếp cận. Và tha thứ cho tôi vì sự khái quát.

Hãy thử 1

Nói rằng bạn là một người nói tiếng Anh bản ngữ. Bạn đến một quốc gia khác, nơi tiếng Anh không phải là ngôn ngữ mẹ đẻ. Bạn cần trợ giúp. Bạn cần một người có thể giúp bạn.

Bạn có hỏi: "Này, bạn sinh ra ở Hoa Kỳ phải không?" Đây là sự kế thừa.

Hay bạn hỏi: "Này, bạn có nói tiếng Anh không"? Đây là giao diện.

Nếu bạn quan tâm đến những gì nó làm, bạn có thể dựa vào giao diện. Nếu bạn quan tâm đến những gì là, bạn dựa vào thừa kế.

Dựa vào thừa kế. Nếu bạn cần một người nói tiếng Anh, thích trà và thích bóng đá, bạn nên phục vụ tốt hơn khi yêu cầu người Anh. :)

Hãy thử 2

Ok, hãy thử một ví dụ khác.

Bạn sử dụng các cơ sở dữ liệu khác nhau và bạn cần triển khai các lớp trừu tượng để làm việc với chúng. Bạn sẽ chuyển lớp của bạn đến một số lớp từ nhà cung cấp DB.

public abstract class SuperDatabaseHelper
{
   void Connect (string User, string Password)
}

public abstract class HiperDatabaseHelper
{
   void Connect (string Password, string User)
}

Đa thừa kế, bạn nói gì? Hãy thử điều đó với trường hợp trên. Bạn không thể. Trình biên dịch sẽ không biết phương thức Connect nào bạn đang cố gắng gọi.

interface ISuperDatabaseHelper
{
  void Connect (string User, string Password)
}

interface IHiperDatabaseHelper
{
   void Connect (string Password, string User)
}

Bây giờ, có một cái gì đó chúng ta có thể làm việc với - ít nhất là trong C # - nơi chúng ta có thể thực hiện các giao diện một cách rõ ràng.

public class MyDatabaseHelper : ISuperDatabaseHelper, IHiperDatabaseHelper
{
   IHiperDataBaseHelper.Connect(string Password, string User)
   {
      //
   }

   ISuperDataBaseHelper.Connect(string User, string Password)
   {
      //
   }

}

Phần kết luận

Các ví dụ không phải là tốt nhất, nhưng tôi nghĩ rằng nó được điểm.

Bạn sẽ chỉ "nhận" giao diện khi bạn cảm thấy cần chúng. Cho đến khi họ sẽ nghĩ rằng họ không dành cho bạn.


Thử đầu tiên là những gì đã cho phiếu bầu của tôi.
osundblad

1
Tôi hoàn toàn sử dụng sự tương tự của người Mỹ và người nói tiếng Anh từ bây giờ. Điều đó thật tuyệt vời.
Bryan Boettcher

Giải thích một cách đơn giản hơn! Tuyệt vời.
Aimal Khan

4

Có 2 lý do chính:

  1. Thiếu nhiều di sản. Bạn có thể kế thừa từ một lớp cơ sở và thực hiện bất kỳ số lượng giao diện nào. Đó là cách duy nhất để "làm" nhiều kế thừa trong .NET.
  2. Khả năng tương tác COM. Bất cứ điều gì sẽ cần được sử dụng bởi các công nghệ "cũ" sẽ cần phải có giao diện được xác định.

Điểm 1 chắc chắn là lý do và lý do được phát triển bởi chính các nhà phát triển microsoft
Pankaj Upadhyay

1
@Pankja Trên thực tế, họ đã lấy ý tưởng giao diện từ Java (giống như một phần tốt trong các tính năng của C #).
Oliver Weiler

3

Việc sử dụng các giao diện giúp một hệ thống được tách rời và do đó dễ dàng hơn để cấu trúc lại, thay đổi và triển khai lại. Đây là một khái niệm rất cốt lõi đối với chính thống hướng đối tượng và lần đầu tiên tôi biết về nó khi các bậc thầy C ++ thực hiện "các lớp trừu tượng thuần túy" khá tương đương với các giao diện.


Việc tách rời rất quan trọng vì nó giữ cho các thành phần khác nhau của một hệ thống độc lập với nhau. Những thay đổi có tác động lớn trong một thành phần cũng không gợn ra các thành phần khác. Hãy nghĩ về phích cắm điện như một giao diện cho công ty tiện ích của bạn (chỉ định điện áp và các chân vật lý và định dạng của phích cắm). Nhờ giao diện này, tiện ích có thể thay đổi hoàn toàn cách họ sản xuất năng lượng (ví dụ: sử dụng công nghệ năng lượng mặt trời), tuy nhiên không có thiết bị nào thậm chí sẽ chú ý thay đổi.
miraculixx

3

Bản thân các giao diện không hữu ích lắm. Nhưng khi được triển khai bởi các lớp cụ thể, bạn thấy rằng nó mang lại cho bạn sự linh hoạt để có một hoặc nhiều triển khai. Phần thưởng là đối tượng sử dụng giao diện không cần biết chi tiết triển khai thực tế diễn ra như thế nào - đó gọi là đóng gói.


2

Chúng chủ yếu được sử dụng để tái sử dụng mã. Nếu bạn viết mã cho giao diện, bạn có thể sử dụng một lớp khác nhau kế thừa từ giao diện đó và không phá vỡ mọi thứ.

Ngoài ra, chúng rất hữu ích trong các dịch vụ web nơi bạn muốn cho khách hàng biết một lớp học làm gì (để họ có thể tiêu thụ nó) nhưng không muốn cung cấp cho họ mã thực tế.


2

Là một lập trình viên / nhà phát triển trẻ, chỉ cần học C #, bạn có thể không thấy sự hữu ích của giao diện, bởi vì bạn có thể viết mã bằng các lớp của mình và mã hoạt động tốt, nhưng trong kịch bản thực tế, xây dựng một ứng dụng có thể mở rộng, mạnh mẽ và có thể bảo trì liên quan đến việc sử dụng một số kiến ​​trúc và các mẫu, chỉ có thể được thực hiện bằng cách sử dụng giao diện, ví dụ là trong tiêm phụ thuộc.


1

Một triển khai thế giới thực:

Bạn có thể truyền một đối tượng làm kiểu Giao diện:

IHelper h = (IHelper)o;
h.HelperMethod();

Bạn có thể tạo một danh sách giao diện

List<IHelper> HelperList = new List<IHelper>();

Với các đối tượng này, bạn có thể truy cập bất kỳ phương thức hoặc thuộc tính giao diện nào. Theo cách này, bạn có thể xác định một giao diện cho phần của chương trình. Và xây dựng logic xung quanh nó. Sau đó, người khác có thể thực hiện giao diện của bạn trong các đối tượng Kinh doanh của họ. Nếu thay đổi của BO, họ có thể thay đổi logic cho các thành phần giao diện và không yêu cầu thay đổi logic cho tác phẩm của bạn.


0

Các giao diện cho vay theo mô đun kiểu plugin bằng cách cung cấp một cơ chế để các lớp hiểu (và đăng ký) một số loại thông báo mà hệ thống của bạn cung cấp. Tôi sẽ giải thích.

Trong ứng dụng của bạn, bạn quyết định rằng bất cứ khi nào một biểu mẫu được tải hoặc tải lại, bạn muốn tất cả những thứ mà nó lưu trữ sẽ bị xóa. Bạn xác định một ICleargiao diện thực hiện Clear. Ngoài ra, bạn quyết định rằng bất cứ khi nào người dùng nhấn nút lưu, biểu mẫu sẽ cố gắng duy trì trạng thái của nó. Vì vậy, mọi thứ tuân theo đều ISavenhận được một thông điệp để duy trì trạng thái của nó. Tất nhiên, thực tế mà nói, hầu hết các giao diện xử lý một số tin nhắn.

Những gì đặt giao diện khác nhau là hành vi phổ biến có thể đạt được mà không cần kế thừa. Lớp thực hiện một giao diện đã cho chỉ đơn giản là hiểu cách ứng xử khi ban hành lệnh (thông báo lệnh) hoặc cách trả lời khi được truy vấn (thông báo truy vấn). Về cơ bản, các lớp trong ứng dụng của bạn hiểu các thông điệp mà ứng dụng của bạn cung cấp. Điều này giúp dễ dàng hơn để xây dựng một hệ thống mô-đun, trong đó mọi thứ có thể được cắm.

Trong hầu hết các ngôn ngữ, có các cơ chế (như LINQ ) để truy vấn những thứ tuân theo giao diện. Điều này thường sẽ giúp bạn loại bỏ logic có điều kiện vì bạn sẽ không phải nói những điều không giống nhau (không cần thiết bắt nguồn từ cùng một chuỗi thừa kế) cách hành xử tương tự (theo một thông điệp cụ thể). Thay vào đó, bạn thu thập mọi thứ hiểu một thông điệp nhất định (tuân theo giao diện) và xuất bản tin nhắn.

Ví dụ: bạn có thể thay thế ...

Me.PublishDate.Clear()
Me.Subject.Clear()
Me.Body.Clear()

...với:

For Each ctl As IClear In Me.Controls.OfType(Of IClear)()
    ctl.Clear()
Next

Mà hiệu quả âm thanh rất nhiều như:

Nghe các ngươi, nghe các ngươi! Xin mọi người hiểu rõ, xin vui lòng Clearngay bây giờ!

Theo cách này, chúng ta có thể lập trình tránh nói với nhau và mọi thứ để tự xóa. Và khi các mục có thể xóa được thêm vào trong tương lai, họ chỉ cần trả lời mà không cần thêm mã.


0

Sau đây là mã giả:

class MyClass{

    private MyInterface = new MyInterfaceImplementationB();

    // Code using Thingy 

}

interface MyInterface{

    myMethod();

}

class MyInterfaceImplementationA{ myMethod(){ // method implementation A } }

class MyInterfaceImplementationB{ myMethod(){ // method implementation B } }

class MyInterfaceImplementationC{ myMethod(){ // method implementation C } }

Các lớp cuối cùng có thể được thực hiện hoàn toàn khác nhau.

Trừ khi nhiều kế thừa là có thể, thừa kế áp đặt việc thực hiện lớp cha làm cho mọi thứ trở nên cứng nhắc hơn. Mặt khác, lập trình chống lại các giao diện có thể cho phép mã hoặc khung của bạn cực kỳ linh hoạt. Nếu bạn từng gặp một trường hợp mà bạn muốn, bạn có thể trao đổi xung quanh các lớp trong chuỗi thừa kế, bạn sẽ hiểu lý do tại sao.

Ví dụ, một khung cung cấp Trình đọc ban đầu dự định đọc dữ liệu từ đĩa có thể được triển khai lại để thực hiện một việc có cùng bản chất nhưng theo một cách hoàn toàn khác. Giống như giải thích mã Morse chẳng hạn.

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.