Tên giao diện có nên bắt đầu bằng tiền tố I I không?


73

Tôi đã được đọc " Clean Code " của Robert Martin để hy vọng trở thành một lập trình viên tốt hơn. Mặc dù cho đến nay vẫn chưa có gì thực sự đột phá, nó khiến tôi nghĩ khác về cách tôi thiết kế các ứng dụng và viết mã.

Có một phần của cuốn sách mà tôi không chỉ không đồng ý mà còn không có ý nghĩa đối với tôi, đặc biệt liên quan đến các quy ước đặt tên giao diện. Đây là văn bản, được lấy trực tiếp từ cuốn sách. Tôi đã nhấn mạnh khía cạnh này tôi thấy khó hiểu và muốn làm rõ trên.

Tôi thích để lại các giao diện chưa được trang bị. Cái trước tôi, rất phổ biến trong các di sản ngày nay, là một sự xao lãng ở mức tốt nhất và quá nhiều thông tin tồi tệ nhất. Tôi không muốn người dùng của mình biết rằng tôi đang trao cho họ một giao diện .

Có lẽ bởi vì tôi chỉ là một sinh viên, hoặc có thể vì tôi chưa bao giờ thực hiện bất kỳ chương trình chuyên nghiệp hoặc lập trình nhóm nào nhưng tôi muốn người dùng biết đó là một giao diện. Có một sự khác biệt lớn giữa việc thực hiện một giao diện và mở rộng một lớp.

Vì vậy, câu hỏi của tôi sôi nổi lên, "Tại sao chúng ta nên che giấu sự thật rằng một số phần của mã đang mong đợi một giao diện?"

Biên tập

Đáp lại câu trả lời:

Nếu loại của bạn là một giao diện hoặc một lớp là doanh nghiệp của bạn, không phải là doanh nghiệp của ai đó sử dụng mã của bạn. Vì vậy, bạn không nên rò rỉ chi tiết về mã của mình trong mã bên thrid này.

Tại sao tôi không nên "rò rỉ" các chi tiết về việc một loại nhất định là giao diện hay lớp đối với mã của bên thứ ba? Điều đó không quan trọng đối với nhà phát triển bên thứ ba sử dụng mã của tôi để biết liệu họ sẽ triển khai giao diện hay mở rộng lớp? Có phải sự khác biệt đơn giản là không quan trọng bằng việc tôi tạo ra chúng trong tâm trí mình?


3
Tôi đồng ý với quan điểm của bạn. Có một điểm khi quá nhiều thông tin ẩn không hữu ích lắm. Tuy nhiên, ngay cả khi bạn làm theo hướng dẫn này, bạn vẫn có thể nói loại sử dụng IDE hoặc tiện ích bổ sung.
NoChance

3
Câu hỏi này về cơ bản được gọi là câu hỏi của "ký hiệu Hungary", bạn nên tìm thấy nhiều lý lẽ và lý do tại sao hầu hết các nhà phát triển không phải là MS đã từ bỏ nó theo từ khóa này. Ký hiệu Hungary chủ yếu là phổ biến cho các biến, nhưng về cơ bản là giống nhau cho các loại.
thiton

2
Chỉnh sửa tiêu đề trước là một trong những khủng khiếp. Câu hỏi này không phải là về ký hiệu Hungary nói chung đơn giản vì nó đề cập đến một quy ước có thể được liên kết với nó. Các giá trị tương đối của HN hoàn toàn không liên quan ở đây; câu hỏi cụ thể là về giao diện so với các lớp và liệu sự khác biệt về ngữ nghĩa có đủ quan trọng / thú vị để biện minh cho một quy ước đặt tên trường hợp đặc biệt hay không.
Aaronaught

Re to know whether they will be implementing an interface or extending a class: có, nhưng hầu hết người dùng mã của bạn sẽ gọi nó, không triển khai hoặc mở rộng nó và họ thực sự không thể quan tâm đó là gì.
david.pfx

Đối với những gì nó có giá trị, tôi ồ ạt thích tiền tố "tôi". Tôi cũng sử dụng tiền tố "Trừu tượng" trên các lớp trừu tượng vì lý do tương tự. Nó không tạo ra sự khác biệt cho người tiêu dùng của lớp / giao diện, nhưng có thể tạo ra sự khác biệt lớn cho những người cần cung cấp phiên bản của nó và cũng làm cho nó đơn giản hơn nhiều đối với các nhà phát triển khác đang đọc mã của bạn. Điều đó có nghĩa là họ có thể thấy trong nháy mắt những gì họ đang giải quyết, thay vì phải tham khảo ý kiến ​​IDE trong từng trường hợp cụ thể để biết thêm thông tin. Tôi mới bắt đầu sử dụng Angular và thấy thật khó chịu khi họ không tuân theo quy ước này!
Dan King

Câu trả lời:


67

Nếu bạn dừng lại để suy nghĩ về nó, bạn sẽ thấy rằng một giao diện thực sự không khác biệt nhiều về mặt ngữ nghĩa so với một lớp trừu tượng:

  • Cả hai đều có phương thức và / hoặc thuộc tính (hành vi);
  • Không nên có các trường không riêng tư (dữ liệu);
  • Không thể được khởi tạo trực tiếp;
  • Xuất phát từ một nghĩa là thực hiện bất kỳ phương thức trừu tượng nào mà nó có, trừ khi kiểu dẫn xuất cũng trừu tượng.

Trong thực tế, sự khác biệt quan trọng nhất giữa các lớp và giao diện là:

  • Giao diện không thể có dữ liệu riêng tư;
  • Các thành viên giao diện không thể có các sửa đổi truy cập (tất cả các thành viên là "công khai");
  • Một lớp có thể thực hiện nhiều giao diện (trái ngược với việc thường có thể kế thừa từ chỉ một lớp cơ sở).

Vì sự khác biệt có ý nghĩa đặc biệt duy nhất giữa các lớp và giao diện xoay quanh (a) dữ liệu riêng và phân cấp kiểu (b) - không tạo ra một chút khác biệt nào cho người gọi - nên thường không cần biết loại đó là giao diện hay một lớp học. Bạn chắc chắn không cần chỉ dẫn trực quan .

Tuy nhiên, có một số trường hợp góc nhất định phải nhận thức được. Đặc biệt, nếu bạn đang sử dụng phản xạ, đánh chặn, proxy / mixin động, dệt mã byte, tạo mã hoặc bất cứ điều gì liên quan đến việc gây rối trực tiếp với hệ thống gõ hoặc mã của môi trường - thì rất hữu ích và đôi khi cần phải biết ngay dù bạn đang làm việc với một giao diện hay một lớp. Bạn rõ ràng không muốn mã của mình thất bại một cách bí ẩn vì bạn đã cố thêm một lớp, thay vì một giao diện, như một hỗn hợp.

Tuy nhiên, đối với mã logic kinh doanh điển hình, vanilla, chạy bộ, sự khác biệt giữa các lớp trừu tượng và giao diện không cần phải được quảng cáo vì chúng sẽ không bao giờ được sử dụng.

Tất cả điều này đang được nói, tôi có xu hướng tiền tố các giao diện C # của tôi bằng Imọi cách vì đó là quy ước .NET được Microsoft sử dụng và ủng hộ. Và khi tôi giải thích các quy ước mã hóa cho một nhà phát triển mới, việc sử dụng các quy tắc của Microsoft sẽ ít rắc rối hơn nhiều so với việc giải thích lý do tại sao chúng ta có các quy tắc "đặc biệt" của riêng mình.


Cảm ơn bạn cho sự cố này. +1 cho "sự khác biệt có ý nghĩa giữa các lớp và giao diện ..."
Charles Sprayberry

24
+1 cho "Tất cả những điều này đã được nói, tôi có xu hướng tiền tố giao diện C # của tôi với tôi vì dù sao đó là quy ước .NET được Microsoft sử dụng và ủng hộ". Đây là lý do đủ cho tôi trong C #. Bằng cách tuân theo tiêu chuẩn chung này, nhiều khả năng các lập trình viên .NET khác xác định giao diện.
Robotsushi

4
Là một người viết cả Java và C #, câu nói "Tất cả những điều này đã được nói, tôi có xu hướng tiền tố các giao diện C # của tôi với tôi bởi vì đó là quy ước .NET được Microsoft sử dụng và ủng hộ" có thể được nhấn mạnh - đó là một trong những điều mà giúp tôi nhớ ngôn ngữ nào tôi đang làm việc,
Aidos

3
Một điểm khác biệt nữa trong .NET (nhưng không phải trong Java) là nhiều ngôn ngữ .NET không cho phép các giao diện chứa các phương thức tĩnh, do đó, việc hack Igiao diện có thể đặt tên tốt cho một lớp để giữ các phương thức tĩnh được liên kết với giao diện (ví dụ: Enumerable<T>.Emptyhoặc Comparer<T>.Default).
supercat

Tôi có một mối quan tâm. Trong C ++ nếu bạn mở một tiêu đề và thấy rằng nó class Foođã được mở rộng class Bar, điều đó không rõ ràng ngay lập tức nếu class Barđược mở rộng hoặc triển khai. Vì vậy, bây giờ bạn phải đi và nhìn vào class Bartiêu đề để quyết định xem có nên sửa đổi class Foođể mở rộng hay không class Baz. Hơn nữa, tiền tố I cung cấp một đầu mối trực quan rõ ràng nếu "lớp cơ sở duy nhất" có bị vi phạm hay không - vì vậy bạn sẽ kiểm tra sự tỉnh táo mỗi khi bạn mở một tiêu đề.
jsj

14

Theo nhiều cách, tính nhất quán quan trọng hơn quy ước. Miễn là bạn nhất quán trong kế hoạch đặt tên của mình, họ sẽ không khó để làm việc. Giao diện tiền tố với một chữ I nếu bạn thích hoặc chỉ để lại tên không được đặt tên, điều đó không quan trọng với tôi miễn là bạn chọn một kiểu và gắn bó với nó!


2
+1 cho tính nhất quán> quy ước. Trong C #, bạn sẽ có tiền tố với I và trong Java, bạn sẽ không. Các nhiệm vụ khác nhau đòi hỏi các quy ước khác nhau
Bringer128

2
+1 trong khi cá nhân tôi không muốn có trên các giao diện của mình, không phù hợp với các thư viện BCL và bên thứ 3 được sử dụng trong các dự án .Net không phải là một tùy chọn imho.
jk.

13

Cuốn sách chứa đầy những thứ hay ho, nhưng tôi vẫn sẽ thêm "I" vào tên giao diện.

Hãy tưởng tượng bạn có public interface ILogmột triển khai mặc định public class Log.

Bây giờ, nếu bạn quyết định có public interface Log, đột nhiên bạn phải thay đổi lớp Log thành public class LogDefaulthoặc một cái gì đó trên các dòng đó. Bạn đã đi từ việc có thêm một nhân vật lên bảy - chắc chắn điều đó thật lãng phí.

Thường có một ranh giới tốt giữa lý thuyết và thực hành. Về lý thuyết đây là một ý tưởng thực sự tốt, nhưng trong thực tế nó không tốt lắm.


Điều này cũng được đề cập trong tài liệu
levininja

30
"Hãy tưởng tượng bạn có ILog giao diện công cộng với Nhật ký lớp công khai triển khai mặc định." - Sau đó, bạn có một tên kém cho việc thực hiện mặc định của bạn. Không gì Loglàm gì? Đăng nhập vào giao diện điều khiển? Để syslog? Không tới đâu cả? Những người nên được gọi ConsoleLog, SyslogLogNullLog, tương ứng. Logkhông phải là một tên tốt cho một lớp cụ thể, bởi vì nó không phải là một tên cụ thể.
Sebastian Redl

7
Cá nhân đây chính xác là lý do tại sao tôi ghét nhìn thấy ITheClassName, bạn chỉ đang tạo một giao diện mà không có lý do gì, có phải nó chỉ là tiếng ồn trên đầu trang của TheClassName. Nếu giao diện của bạn có mục đích, bạn nên đặt tên tốt hơn ITheClassName
Richard Tingle

Tên của lớp được sử dụng một lần (để khởi tạo), tên của giao diện được sử dụng ở mọi nơi. Thêm một chữ cái vào giao diện để lưu chữ cái trên tên lớp là kinh tế sai (của các ký tự).
sergut

@RichardTingle Nhưng tôi nghĩ cách sử dụng phổ biến chỉ đơn giản là MyClasscó một biến thể có thể nhạo báng , phải không? Đó là, chúng tôi thường sử dụng các giao diện để làm cho các phương thức công khai thực sự công khai theo cách cho phép thử nghiệm. (Không nói đó là tốt hay xấu, nhưng sự hiểu biết rằng động lực cho các giao diện thường chỉ đơn giản là để làm cho các lớp học mà phụ thuộc một cách dễ dàng mockable không giải thích 1-to-1 MyClassđể IMyClassánh xạ.)
ruffin

8

Vâng, đây không phải là về việc thực hiện giao diện hoặc mở rộng một lớp. Trong trường hợp thoses, dù sao bạn cũng biết những gì bạn đang làm.

Tuy nhiên, khi mã của bên thứ ba (một mô-đun khác của ứng dụng mẫu) thao túng dữ liệu của bạn, mã này sẽ không quan tâm nếu bạn đang trình bày một giao diện hoặc một lớp.

Đây là toàn bộ điểm trừu tượng. Bạn đang trình bày cho mã bên thứ ba này một đối tượng của một loại nhất định. Loại đã cho này có một số chức năng thành viên bạn có thể gọi. Thế là đủ rồi.

Nếu loại của bạn là một giao diện hoặc một lớp là doanh nghiệp của bạn, không phải là doanh nghiệp của ai đó sử dụng mã của bạn. Vì vậy, bạn không nên rò rỉ chi tiết mã của mình sang mã bên thứ ba này.

Nhân tiện, giao diện và các lớp là loại tham chiếu ở cuối. Và đây là những gì quan trọng. Vì vậy, đây là những gì quy ước đặt tên của bạn phải nhấn mạnh.


@Mat> Vâng, đó là một lỗi của tôi và tôi đã chỉnh sửa nó.
deadalnix

5

Hầu hết các câu trả lời dường như cho rằng ngôn ngữ lập trình là Java hoặc C # trong đó có một khái niệm (hoặc từ khóa) cho các giao diện / lớp trừu tượng. Trong những trường hợp này, trong một IDE tốt, nó có thể được nhìn thấy ngay lập tức với loại giao dịch lớp một và văn bản public interface IMyClasslà sự trùng lặp không cần thiết. Nó giống như bạn sẽ không viết public final FinalMyClass- hãy tưởng tượng đặt mọi từ khóa vào tên lớp.

Tuy nhiên, theo tôi trong C ++, tình huống hơi khác một chút khi người ta phải đi sâu vào tệp tiêu đề và xem liệu lớp có bất kỳ phương thức ảo nào để tìm hiểu xem nó có phải là một lớp trừu tượng không. Trong trường hợp đó, tôi có thể thấy rõ một đối số để viết class AbstractMyClass.

Vì vậy, câu trả lời của tôi sẽ là: Nó phụ thuộc vào ngôn ngữ lập trình.

Cập nhật 2016: 2 năm kinh nghiệm về C ++ sau này bây giờ tôi có thể coi đó là cách thực hành tồi đối với các tên lớp tiền tố Abstract, mặc dù tôi có thể nói rằng có lẽ các cơ sở mã phức tạp đến mức có thể có ý nghĩa.


Bạn có chắc chắn điều này trả lời câu hỏi? Bạn có thể muốn đọc các câu trả lời khác và làm rõ một số điểm của bạn.
david.pfx

C ++ chắc chắn có giao diện, ngay cả khi không có từ khóa cho nó. Bạn gọi một lớp trong đó mọi hàm thành viên là thuần ảo và không có biến thành viên?

@ david.pfx: Tôi nghĩ rằng tôi trả lời chính xác câu hỏi "Tên giao diện có nên bắt đầu bằng tiền tố I I không?": Nó phụ thuộc vào ngôn ngữ lập trình. Nếu bạn nghĩ rằng công phu của tôi không đủ rõ ràng, tôi rất vui lòng cải thiện nó - phần nào không rõ ràng cho bạn?
Ela782

2
@JohnGaughan: Chắc chắn nó có giao diện! Nhưng toàn bộ quan điểm của tôi về từ khóa. C ++ không có, vì vậy IDE / người dùng sẽ không hiển thị nếu anh ấy / cô ấy giao dịch với giao diện hay không. Trong Java, tuy nhiên, nó có thể nhìn thấy ngay lập tức.
Ela782

1
Đọc câu trả lời hàng đầu và so sánh của bạn. Bạn chưa quen với SO và đây là cơ hội để tìm hiểu loại câu trả lời nào thu hút phiếu bầu. Khi nó đứng, bạn sẽ không. Với nhiều công việc hơn, giải thích nhiều hơn, nhiều giá trị hơn, nó chỉ có thể. Treo ở đó!
david.pfx

4

Thực hiện theo các thành ngữ của ngôn ngữ bạn đang sử dụng.

Mỗi ngôn ngữ có thành ngữ và hướng dẫn mã hóa riêng. Ví dụ, trong C #, nó là thành ngữ cho các giao diện tiền tố với I. Trong Go, thì không.


+1 Thực hiện theo các thành ngữ của ngôn ngữ bạn đang sử dụng. Rõ ràng tác giả cuốn sách là một nhà phát triển Java. .NET / C #: ILog Java: Log Nhưng nhược điểm: Khi tôi thích có một lớp Log thực hiện giao diện ILog .... MyLog, LogDefault, LogBase, ...? Xấu xí phải không? Xấu xí hơn là: LogImpl ....: D
hfrmobile

0

Trong mã (Java) của tôi, tôi có xu hướng có quy ước này trong các API mà tôi trưng ra cho người gọi:

  • Chức năng được cung cấp thông qua các giao diện, và không bao giờ bởi các lớp.
  • Các bộ phận phi chức năng là các lớp.

Theo phi chức năng, ý tôi là những thứ như cấu trúc dữ liệu thuần túy (chẳng hạn như các lớp đóng vai trò là cầu nối cho tuần tự hóa XML hoặc ORM), liệt kê và ngoại lệ, tất cả đều không thể là giao diện (tốt, bạn có thể cho các lớp dữ liệu thuần túy , nhưng đó là rất nhiều công việc để kiếm được rất ít vì không có gì mà các lớp đó làm ngoại trừ việc giữ dữ liệu).

Về mặt quy ước đặt tên, các giao diện có xu hướng ánh xạ tới các danh từ diễn viên (ví dụ FooBarWatcher:) hoặc tính từ (ví dụ FooBarWatchable) và cả các lớp dữ liệu thuần túy và ánh xạ liệt kê thành các danh từ không hoạt động (ví dụ FooBarStatus:); IDE có thể hướng dẫn người tiêu dùng API mà không cần quy ước đặt tên đặc biệt. Trường hợp ngoại lệ theo quy ước Java thông thường ( FooBarException, FooBarError, FooBarFault) tất nhiên.

Tôi cũng sẽ thường xuyên đặt các giao diện trong gói riêng của họ hoặc thậm chí trong thư viện của riêng họ, chỉ để đảm bảo rằng tôi không muốn phá vỡ các quy tắc của riêng mình. (Điều này cũng giúp tôi quản lý bản dựng khi tôi lấy mã từ các nguồn bên ngoài như tài liệu WSDL.)


Tôi cũng không bao giờ đặt Itiền tố vào giao diện. Tất nhiên đó là một giao diện! Đó là trong một API (hoặc SPI)!
Donal Fellows
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.