Tại sao một lớp học phải là bất cứ thứ gì khác ngoài bản tóm tắt hay khác


29

Sau hơn 10 năm lập trình java / c #, tôi thấy mình cũng đang tạo ra:

  • lớp trừu tượng : hợp đồng không có nghĩa là ngay lập tức.
  • lớp cuối cùng / niêm phong : việc thực hiện không có nghĩa là phục vụ như lớp cơ sở cho thứ khác.

Tôi không thể nghĩ về bất kỳ tình huống nào mà một "lớp" đơn giản (nghĩa là không trừu tượng hay cuối cùng / niêm phong) sẽ là "lập trình khôn ngoan".

Tại sao một lớp nên là bất cứ thứ gì khác ngoài "trừu tượng" hoặc "cuối cùng / niêm phong"?

CHỈNH SỬA

Bài viết tuyệt vời này giải thích mối quan tâm của tôi tốt hơn nhiều so với tôi có thể.


21
Bởi vì nó được gọi là Open/Closed principle, chứ không phảiClosed Principle.
StuperUser

2
Những loại điều bạn đang viết chuyên nghiệp? Nó rất có thể ảnh hưởng đến ý kiến ​​của bạn về vấn đề này.

Vâng, tôi biết một số nhà phát triển nền tảng đã niêm phong mọi thứ, bởi vì họ muốn giảm thiểu giao diện thừa kế.
K ..

4
@StuperUser: Đó không phải là một lý do, đó là một mức độ. OP không hỏi độ cao là gì, anh ấy hỏi tại sao . Nếu không có lý do đằng sau một nguyên tắc, không có lý do để chú ý đến nó.
Michael Shaw

1
Tôi tự hỏi có bao nhiêu khung UI sẽ phá vỡ bằng cách thay đổi lớp Window thành niêm phong.
Phản ứng

Câu trả lời:


46

Trớ trêu thay, tôi lại thấy điều ngược lại: việc sử dụng các lớp trừu tượng là ngoại lệ chứ không phải là quy tắc và tôi có xu hướng nhăn mặt trên các lớp cuối cùng / niêm phong.

Các giao diện là một cơ chế thiết kế theo hợp đồng điển hình hơn vì bạn không chỉ định bất kỳ nội bộ nào - bạn không lo lắng về chúng. Nó cho phép mọi thực hiện hợp đồng đó được độc lập. Đây là chìa khóa trong nhiều lĩnh vực. Ví dụ: nếu bạn đang xây dựng ORM, điều rất quan trọng là bạn có thể chuyển truy vấn đến cơ sở dữ liệu theo cách thống nhất, nhưng việc triển khai có thể hoàn toàn khác. Nếu bạn sử dụng các lớp trừu tượng cho mục đích này, bạn sẽ kết nối cứng trong các thành phần có thể hoặc không thể áp dụng cho tất cả các triển khai.

Đối với các lớp cuối cùng / niêm phong, lý do duy nhất tôi có thể thấy khi sử dụng chúng là khi thực sự nguy hiểm khi cho phép ghi đè - có thể là thuật toán mã hóa hoặc thứ gì đó. Ngoài ra, bạn không bao giờ biết khi nào bạn có thể muốn mở rộng chức năng vì lý do địa phương. Niêm phong một lớp giới hạn các tùy chọn của bạn cho lợi ích không tồn tại trong hầu hết các kịch bản. Sẽ linh hoạt hơn nhiều khi viết các lớp của bạn theo cách mà chúng có thể được mở rộng sau này xuống dòng.

Quan điểm thứ hai này đã được củng cố cho tôi bằng cách làm việc với các thành phần bên thứ 3 niêm phong các lớp do đó ngăn chặn một số tích hợp sẽ làm cho cuộc sống dễ dàng hơn nhiều.


17
+1 cho đoạn cuối. Tôi thường thấy quá nhiều sự đóng gói trong các thư viện của bên thứ 3 (hoặc thậm chí các lớp thư viện tiêu chuẩn!) Là một nguyên nhân gây đau đớn lớn hơn so với việc đóng gói quá ít.
Mason Wheeler

5
Đối số thông thường để niêm phong các lớp là bạn không thể dự đoán nhiều cách khác nhau mà khách hàng có thể ghi đè lên lớp của bạn và do đó bạn không thể đảm bảo về hành vi của nó. Xem blog.msdn.com/b/ericlippert/archive/2004/01/22/iêu
Robert Harvey

12
@RobertHarvey Tôi quen thuộc với các đối số và nó có vẻ tuyệt vời trong lý thuyết. Bạn với tư cách là người thiết kế đối tượng không thể thấy trước cách mọi người có thể mở rộng các lớp học của bạn - đó chính xác là lý do tại sao họ không nên bị niêm phong. Bạn không thể hỗ trợ mọi thứ - tốt thôi. Đừng. Nhưng cũng đừng bỏ đi lựa chọn nào.
Michael

6
@RobertHarvey không phải chỉ là những người phá vỡ LSP có được những gì họ xứng đáng?
StuperUser

2
Tôi cũng không phải là một fan hâm mộ lớn của các lớp niêm phong, nhưng tôi có thể hiểu tại sao một số công ty như Microsoft (những người thường xuyên phải hỗ trợ những thứ mà họ không tự phá vỡ) lại thấy chúng hấp dẫn. Người dùng của một khung không nhất thiết phải có kiến ​​thức về các phần bên trong của lớp.
Robert Harvey

11

Đó một bài viết tuyệt vời của Eric Lippert, nhưng tôi không nghĩ nó hỗ trợ cho quan điểm của bạn.

Ông lập luận rằng tất cả các lớp tiếp xúc với người khác sử dụng nên được niêm phong, hoặc nói cách khác là không thể mở rộng.

Tiền đề của bạn là tất cả các lớp nên trừu tượng hoặc niêm phong.

Sự khác biệt lớn.

Bài báo của EL không nói gì về các lớp (có lẽ là nhiều) do nhóm của anh ấy sản xuất mà bạn và tôi không biết gì về nó. Nói chung, các lớp tiếp xúc công khai trong một khung chỉ là một tập hợp con của tất cả các lớp liên quan đến việc thực hiện khung đó.


Nhưng bạn có thể áp dụng cùng một đối số cho các lớp không phải là một phần của giao diện chung. Một trong những lý do chính để thực hiện một trận chung kết lớp là nó hoạt động như một biện pháp an toàn để ngăn chặn mã cẩu thả. Đối số đó là hợp lệ cho bất kỳ cơ sở mã nào được chia sẻ bởi các nhà phát triển khác nhau theo thời gian hoặc ngay cả khi bạn là nhà phát triển duy nhất. Nó chỉ bảo vệ ngữ nghĩa của mã.
DPM

Tôi nghĩ rằng ý tưởng rằng các lớp nên trừu tượng hoặc được niêm phong là một phần của nguyên tắc rộng hơn, đó là người ta nên tránh sử dụng các biến của các loại lớp khả thi. Việc tránh như vậy sẽ giúp tạo ra một loại có thể được sử dụng bởi người tiêu dùng của một loại nhất định, mà không phải thừa kế tất cả các thành viên tư nhân. Thật không may, các thiết kế như vậy không thực sự hoạt động với cú pháp của nhà xây dựng công cộng. Thay vào đó, mã sẽ phải thay thế new List<Foo>()bằng một cái gì đó như List<Foo>.CreateMutable().
supercat

5

Từ quan điểm java tôi nghĩ rằng các lớp cuối cùng không thông minh như nó có vẻ.

Nhiều công cụ (đặc biệt là AOP, JPA, v.v.) hoạt động với thời gian tải chờ để chúng phải mở rộng đầu mối của bạn. Một cách khác là tạo các đại biểu (không phải .NET) ủy thác mọi thứ cho lớp ban đầu, điều này sẽ lộn xộn hơn nhiều so với việc mở rộng các lớp người dùng.


5

Hai trường hợp phổ biến trong đó bạn sẽ cần vanilla, các lớp không kín:

  1. Kỹ thuật: Nếu bạn có một hệ thống phân cấp sâu hơn hai cấp độ và bạn muốn có thể khởi tạo một cái gì đó ở giữa.

  2. Nguyên tắc: Đôi khi mong muốn viết các lớp có tính khám phá được thiết kế để được mở rộng một cách an toàn . (Điều này xảy ra rất nhiều khi bạn đang viết một API như Eric Lippert hoặc khi bạn làm việc trong một nhóm trong một dự án lớn). Đôi khi bạn muốn tự mình viết một lớp hoạt động tốt, nhưng nó được thiết kế với khả năng mở rộng.

Suy nghĩ Eric Lippert về làm cho niêm phong cảm, nhưng ông cũng thừa nhận rằng họ làm thiết kế cho khả năng mở rộng bằng cách rời khỏi lớp học "mở".

Vâng, nhiều lớp được niêm phong trong BCL, nhưng một số lượng lớn các lớp thì không, và có thể được mở rộng theo đủ mọi cách tuyệt vời. Một ví dụ xuất hiện trong Windows Forms, nơi bạn có thể thêm dữ liệu hoặc hành vi vào hầu hết mọi thứ Controlthông qua kế thừa. Chắc chắn, điều này có thể đã được thực hiện theo những cách khác (mô hình trang trí, các loại thành phần khác nhau, v.v.), nhưng kế thừa cũng hoạt động rất tốt.

Hai ghi chú cụ thể của .NET:

  1. Trong hầu hết các trường hợp, các lớp niêm phong thường không quan trọng đối với sự an toàn, bởi vì những người thừa kế không thể gây rối với virtualchức năng không của bạn , ngoại trừ việc triển khai giao diện rõ ràng.
  2. Đôi khi, một giải pháp thay thế phù hợp là tạo Trình xây dựng internalthay vì niêm phong lớp, cho phép nó được kế thừa bên trong cơ sở mã của bạn, nhưng không phải bên ngoài nó.

4

Tôi tin rằng lý do thực sự khiến nhiều người cảm thấy các lớp nên final/ sealedlà hầu hết các lớp mở rộng không trừu tượng không được ghi lại đúng cách .

Hãy để tôi giải thích. Bắt đầu từ xa, có một quan điểm trong số một số lập trình viên rằng sự kế thừa như một công cụ trong OOP bị lạm dụng và lạm dụng rộng rãi. Tất cả chúng ta đều đã đọc nguyên tắc thay thế Liskov, mặc dù điều này không ngăn chúng ta vi phạm nó hàng trăm (thậm chí hàng ngàn) lần.

Điều này là các lập trình viên thích sử dụng lại mã. Ngay cả khi nó không phải là một ý tưởng tốt. Và kế thừa là một công cụ quan trọng trong "reabusing" mã này. Quay lại câu hỏi cuối cùng / niêm phong.

Tài liệu phù hợp cho một lớp cuối cùng / niêm phong là tương đối nhỏ: bạn mô tả mỗi phương thức làm gì, các đối số, giá trị trả về, v.v ... Tất cả các công cụ thông thường.

Tuy nhiên, khi bạn viết tài liệu đúng về một lớp có thể mở rộng, bạn phải bao gồm ít nhất những điều sau đây :

  • Sự phụ thuộc giữa các phương thức (phương thức nào gọi, v.v.)
  • Phụ thuộc vào các biến cục bộ
  • Hợp đồng nội bộ mà lớp mở rộng nên tôn vinh
  • Quy ước cuộc gọi cho mỗi phương thức (ví dụ: Khi bạn ghi đè lên nó, bạn có gọi lệnh superthực hiện không? Bạn có gọi nó ở đầu phương thức hay cuối cùng không? Hãy nghĩ hàm tạo so với hàm hủy)
  • ...

Đây chỉ là trên đỉnh đầu của tôi. Và tôi có thể cung cấp cho bạn một ví dụ về lý do tại sao mỗi trong số này là quan trọng và bỏ qua nó sẽ làm hỏng một lớp mở rộng.

Bây giờ, hãy xem xét bao nhiêu nỗ lực tài liệu nên đi vào tài liệu đúng từng điều này. Tôi tin rằng một lớp học có 7-8 phương thức (có thể quá nhiều trong một thế giới lý tưởng hóa, nhưng quá ít trong thực tế) cũng có thể có một tài liệu khoảng 5 trang, chỉ có văn bản. Vì vậy, thay vào đó, chúng tôi tránh ra giữa chừng và không niêm phong lớp học, để những người khác có thể sử dụng nó, nhưng cũng không ghi chép đúng, vì nó sẽ mất một lượng thời gian khổng lồ (và, bạn biết đấy, nó có thể Dù sao cũng không bao giờ được gia hạn, vậy tại sao phải bận tâm?).

Nếu bạn đang thiết kế một lớp học, bạn có thể cảm thấy sự cám dỗ để niêm phong nó để mọi người không thể sử dụng nó theo cách mà bạn không lường trước được (và chuẩn bị cho). Mặt khác, khi bạn đang sử dụng mã của người khác, đôi khi từ API công khai không có lý do rõ ràng nào cho lớp là cuối cùng và bạn có thể nghĩ "Chết tiệt, điều này chỉ khiến tôi mất 30 phút để tìm cách giải quyết".

Tôi nghĩ rằng một số yếu tố của một giải pháp là:

  • Đầu tiên để đảm bảo mở rộng là một ý tưởng hay khi bạn là khách hàng của mã và để thực sự ủng hộ thành phần hơn kế thừa.
  • Thứ hai để đọc toàn bộ hướng dẫn sử dụng (một lần nữa với tư cách là khách hàng) để đảm bảo bạn không nhìn thấy thứ gì đó được đề cập.
  • Thứ ba, khi bạn đang viết một đoạn mã khách hàng sẽ sử dụng, hãy viết tài liệu phù hợp cho mã (vâng, đường dài). Một ví dụ tích cực, tôi có thể cung cấp tài liệu iOS của Apple. Chúng không đủ để người dùng luôn mở rộng đúng các lớp của mình, nhưng ít nhất chúng bao gồm một số thông tin về thừa kế. Đó là nhiều hơn tôi có thể nói cho hầu hết các API.
  • Thứ tư, thực sự cố gắng mở rộng lớp học của riêng bạn, để đảm bảo nó hoạt động. Tôi là một người ủng hộ lớn bao gồm nhiều mẫu và thử nghiệm trong API và khi bạn thực hiện thử nghiệm, bạn cũng có thể kiểm tra chuỗi thừa kế: sau tất cả chúng là một phần trong hợp đồng của bạn!
  • Thứ năm, trong các tình huống khi bạn nghi ngờ, chỉ ra rằng lớp học không có nghĩa là được mở rộng và thực hiện nó là một ý tưởng tồi (tm). Cho biết bạn không nên chịu trách nhiệm cho việc sử dụng ngoài ý muốn như vậy, nhưng vẫn không niêm phong lớp học. Rõ ràng, điều này không bao gồm các trường hợp khi lớp nên được niêm phong 100%.
  • Cuối cùng, khi niêm phong một lớp, cung cấp một giao diện như một móc trung gian, để khách hàng có thể "viết lại" phiên bản sửa đổi của lớp mình và làm việc xung quanh lớp 'niêm phong' của bạn. Bằng cách này, anh ta có thể thay thế lớp niêm phong bằng việc thực hiện của mình. Bây giờ, điều này là rõ ràng, vì nó là khớp nối lỏng lẻo ở dạng đơn giản nhất của nó, nhưng nó vẫn đáng được đề cập.

Cũng đáng để đề cập đến câu hỏi "triết học" sau đây: Liệu một lớp là sealed/ finalmột phần của hợp đồng cho lớp học, hay một chi tiết thực hiện? Bây giờ tôi không muốn bước đi ở đó, nhưng một câu trả lời cho điều này cũng sẽ ảnh hưởng đến quyết định của bạn có nên niêm phong một lớp học hay không.


3

Một lớp không nên là cuối cùng / niêm phong hoặc trừu tượng nếu:

  • Bản thân nó rất hữu ích, tức là có ích khi có các thể hiện của lớp đó.
  • Nó có lợi cho lớp đó là lớp con / lớp cơ sở của các lớp khác.

Ví dụ: lấy ObservableCollection<T>lớp trong C # . Nó chỉ cần thêm việc tăng các sự kiện vào các hoạt động bình thường của a Collection<T>, đó là lý do tại sao nó phân lớp Collection<T>. Collection<T>là một lớp khả thi trên chính nó, và vì vậy nó ObservableCollection<T>.


Nếu tôi phụ trách việc này, có lẽ tôi sẽ làm CollectionBase(trừu tượng), Collection : CollectionBase(niêm phong), ObservableCollection : CollectionBase(niêm phong). Nếu bạn nhìn vào Bộ sưu tập <T> một cách chặt chẽ, bạn sẽ thấy đó là một lớp trừu tượng nửa khẳng định.
Nicolas Repiquet

2
Lợi thế nào bạn có được từ việc có ba lớp thay vì chỉ hai lớp? Ngoài ra, làm thế nào là Collection<T>một "lớp trừu tượng nửa khẳng định"?
FishBasketGordo

Collection<T>phơi bày rất nhiều bộ phận thông qua các phương thức và thuộc tính được bảo vệ, và rõ ràng có nghĩa là một lớp cơ sở cho bộ sưu tập chuyên biệt. Nhưng không rõ bạn nên đặt mã của mình ở đâu, vì không có phương thức trừu tượng nào để thực hiện. ObservableCollectionkế thừa từ Collectionvà không được niêm phong, vì vậy bạn có thể lại kế thừa từ nó. Và bạn có thể truy cập vào Itemstài sản được bảo vệ, cho phép bạn thêm các mục trong bộ sưu tập mà không gây ra sự kiện ... Đẹp.
Nicolas Repiquet

@NicolasRepiquet: Trong nhiều ngôn ngữ và khung, các phương tiện thành ngữ thông thường để tạo một đối tượng yêu cầu loại biến sẽ giữ đối tượng giống với loại của thể hiện được tạo. Trong nhiều trường hợp, cách sử dụng lý tưởng sẽ là chuyển các tham chiếu đến một kiểu trừu tượng, nhưng điều đó sẽ buộc rất nhiều mã sử dụng một loại cho các biến và tham số và một loại cụ thể khác khi gọi các hàm tạo. Khó có thể, nhưng một chút khó xử.
supercat

3

Vấn đề với các lớp cuối cùng / niêm phong là họ đang cố gắng giải quyết vấn đề chưa xảy ra. Nó chỉ hữu ích khi sự cố tồn tại, nhưng thật bực bội vì bên thứ ba đã áp đặt một hạn chế. Hiếm khi lớp niêm phong giải quyết một vấn đề hiện tại, điều này gây khó khăn cho việc tranh luận về tính hữu dụng của nó.

Có những trường hợp một lớp nên được niêm phong. Ví dụ như; Lớp quản lý các tài nguyên / bộ nhớ được phân bổ theo cách mà nó không thể dự đoán được những thay đổi trong tương lai có thể thay đổi sự quản lý đó như thế nào.

Trong những năm qua, tôi đã thấy đóng gói, các cuộc gọi lại và các sự kiện trở nên linh hoạt / hữu ích hơn nhiều so với các lớp trừu tượng. Tôi thấy rất nhiều mã với một hệ thống phân cấp lớn các lớp trong đó việc đóng gói và các sự kiện sẽ làm cho cuộc sống đơn giản hơn cho nhà phát triển.


1
Công cụ được niêm phong cuối cùng trong phần mềm giải quyết vấn đề "Tôi cảm thấy cần phải áp đặt ý chí của mình lên những người duy trì mã này trong tương lai".
Kaz

Không phải là cuối cùng / đóng dấu một cái gì đó được thêm vào OOP, vì tôi không nhớ nó ở xung quanh khi tôi còn trẻ. Có vẻ như sau khi nghĩ về loại tính năng.
Phản ứng

Hoàn thiện tồn tại như một thủ tục chuỗi công cụ trong các hệ thống OOP trước khi OOP trở nên ngớ ngẩn với các ngôn ngữ như C ++ và Java. Các lập trình viên làm việc ở Smalltalk, Lisp với sự linh hoạt tối đa: mọi thứ đều có thể được mở rộng, các phương thức mới được thêm vào mọi lúc. Sau đó, hình ảnh được biên dịch của hệ thống phải được tối ưu hóa: một giả định được đưa ra là hệ thống sẽ không được người dùng cuối mở rộng, và do đó, điều này có nghĩa là việc gửi phương thức có thể được tối ưu hóa dựa trên việc nắm bắt phương thức nào và các lớp tồn tại bây giờ .
Kaz

Tôi không nghĩ đó là điều tương tự, bởi vì đây chỉ là một tính năng tối ưu hóa. Tôi không nhớ đã niêm phong trong tất cả các phiên bản Java, nhưng tôi có thể sai vì tôi không sử dụng nó nhiều.
Phản ứng

Chỉ vì nó biểu hiện như một số tuyên bố mà bạn phải đưa vào mã không có nghĩa là nó không giống nhau.
Kaz

2

"Niêm phong" hoặc "hoàn thiện" trong các hệ thống đối tượng cho phép tối ưu hóa nhất định, bởi vì biểu đồ công văn hoàn chỉnh đã biết.

Điều đó có nghĩa là, chúng tôi làm cho hệ thống khó thay đổi thành một thứ khác, như một sự đánh đổi cho hiệu suất. (Đó là bản chất của hầu hết các tối ưu hóa.)

Trong tất cả các khía cạnh khác, đó là một mất mát. Các hệ thống nên được mở và mở rộng theo mặc định. Thật dễ dàng để thêm các phương thức mới cho tất cả các lớp và mở rộng tùy ý.

Chúng tôi không đạt được bất kỳ chức năng mới nào hôm nay bằng cách thực hiện các bước để ngăn chặn việc mở rộng trong tương lai.

Vì vậy, nếu chúng ta làm điều đó vì mục đích phòng ngừa, thì những gì chúng ta đang làm là cố gắng kiểm soát cuộc sống của những người duy trì trong tương lai. Đó là về bản ngã. "Ngay cả khi tôi không còn làm việc ở đây, mã này sẽ được duy trì theo cách của tôi, chết tiệt!"


1

Các lớp kiểm tra dường như đến với tâm trí. Đây là các lớp được gọi theo kiểu tự động hoặc "tùy ý" dựa trên những gì lập trình viên / người kiểm thử đang cố gắng thực hiện. Tôi không chắc chắn tôi đã từng thấy hay nghe về một lớp kiểm tra đã hoàn thành riêng tư.


Bạn đang nói về cái gì vậy? Theo cách nào thì các lớp phải kiểm tra không phải là cuối cùng / niêm phong / trừu tượng?

1

Thời gian khi bạn cần xem xét một lớp dự định sẽ được mở rộng là khi bạn đang thực hiện một số kế hoạch thực sự cho tương lai. Hãy để tôi cho bạn một ví dụ thực tế từ công việc của tôi.

Tôi dành nhiều thời gian để viết các công cụ giao diện giữa sản phẩm chính của chúng tôi và các hệ thống bên ngoài. Khi chúng tôi thực hiện bán hàng mới, một thành phần lớn là một nhóm các nhà xuất khẩu được thiết kế để chạy theo định kỳ, tạo ra các tệp dữ liệu chi tiết các sự kiện đã xảy ra ngày hôm đó. Những tệp dữ liệu này sau đó được sử dụng bởi hệ thống của khách hàng.

Đây là một cơ hội tuyệt vời để mở rộng các lớp học.

Tôi có một lớp Xuất khẩu là lớp cơ sở của mọi nhà xuất khẩu. Nó biết cách kết nối với cơ sở dữ liệu, tìm ra nơi nó đã chạy lần cuối và chạy lưu trữ các tệp dữ liệu mà nó tạo ra. Nó cũng cung cấp quản lý tập tin tài sản, ghi nhật ký và một số xử lý ngoại lệ đơn giản.

Trên hết, tôi có một nhà xuất khẩu khác nhau để làm việc với từng loại dữ liệu, có lẽ có hoạt động người dùng, dữ liệu giao dịch, dữ liệu quản lý tiền mặt, v.v.

Trên cùng của ngăn xếp này, tôi đặt một lớp dành riêng cho khách hàng, thực hiện cấu trúc tệp dữ liệu mà khách hàng cần.

Theo cách này, nhà xuất khẩu cơ sở rất hiếm khi thay đổi. Các nhà xuất khẩu kiểu dữ liệu cốt lõi đôi khi thay đổi nhưng hiếm khi và thường chỉ xử lý các thay đổi lược đồ cơ sở dữ liệu nên được truyền tới tất cả các khách hàng. Công việc duy nhất tôi từng phải làm cho mỗi khách hàng là một phần của mã dành riêng cho khách hàng đó. Một thế giới hoàn hảo!

Vì vậy, cấu trúc trông như:

Base
 Function1
  Customer1
  Customer2
 Function2
 ...

Quan điểm chính của tôi là bằng cách kiến ​​trúc mã theo cách này tôi có thể sử dụng kế thừa chủ yếu để sử dụng lại mã.

Tôi phải nói rằng tôi không thể nghĩ ra bất kỳ lý do nào để vượt qua ba lớp.

Tôi đã sử dụng hai lớp nhiều lần, ví dụ để có một Tablelớp chung thực hiện các truy vấn bảng cơ sở dữ liệu trong khi các lớp con Tablethực hiện các chi tiết cụ thể của mỗi bảng bằng cách sử dụng một enumđể xác định các trường. Để việc enumthực hiện một giao diện được xác định trong Tablelớp có ý nghĩa.


1

Tôi đã tìm thấy các lớp trừu tượng hữu ích nhưng không phải lúc nào cũng cần thiết và các lớp kín trở thành một vấn đề khi áp dụng các bài kiểm tra đơn vị. Bạn không thể chế nhạo hoặc bỏ qua một lớp niêm phong, trừ khi bạn sử dụng thứ gì đó giống như Telmiks justmock.


1
Đây là một nhận xét tốt, nhưng không trả lời trực tiếp câu hỏi. Hãy xem xét mở rộng suy nghĩ của bạn ở đây.

1

Tôi đồng ý với quan điểm của bạn. Tôi nghĩ rằng trong Java, theo mặc định, các lớp nên được khai báo là "cuối cùng". Nếu bạn không làm cho nó cuối cùng, sau đó đặc biệt chuẩn bị nó và ghi lại nó để gia hạn.

Lý do chính cho điều này là để đảm bảo rằng bất kỳ trường hợp nào trong các lớp của bạn sẽ tuân theo giao diện mà bạn đã thiết kế và ghi lại ban đầu. Mặt khác, một nhà phát triển sử dụng các lớp của bạn có thể có khả năng tạo mã dễ vỡ và không nhất quán và đến lượt nó, chuyển nó cho các nhà phát triển / dự án khác, làm cho các đối tượng của các lớp của bạn không đáng tin cậy.

Từ góc độ thực tế hơn, thực sự có một nhược điểm, vì các máy khách của giao diện thư viện của bạn sẽ không thể thực hiện bất kỳ điều chỉnh nào và sử dụng các lớp của bạn theo những cách linh hoạt hơn mà bạn nghĩ ban đầu.

Cá nhân, đối với tất cả các mã chất lượng kém tồn tại (và vì chúng ta đang thảo luận về điều này ở mức độ thực tế hơn, tôi sẽ cho rằng sự phát triển Java dễ bị điều này hơn) Tôi nghĩ rằng sự cứng nhắc này là một cái giá nhỏ để trả cho việc tìm kiếm của chúng tôi dễ dàng hơn duy trì mã.

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.