2009-09-20 20 views
9

Tại sao bất kỳ ai muốn đánh dấu một lớp học là cuối cùng hoặc niêm phong?Mục đích cuối cùng và được đóng dấu

+2

Tiêu đề không phải là một câu hỏi thực sự. – spender

+12

Bởi vì lớp học không muốn có con và chúng ta nên tôn trọng mong muốn của nó. :) – klabranche

+3

@klabranche: Hãy cho tôi biết khi họ thay đổi nó thành một lớp 'spayed' hoặc 'neutered'. –

Trả lời

14

Theo Wikipedia, "Các lớp được niêm phong chủ yếu được sử dụng để ngăn chặn dẫn xuất. Chúng thêm một mức độ nghiêm ngặt khác trong thời gian biên dịch, cải thiện mức sử dụng bộ nhớ và kích hoạt tối ưu nhất định để cải thiện hiệu quả thời gian chạy."

Ngoài ra, từ Patrick Smacchia's blog:

  • Versioning: Khi một lớp được bịt kín ban đầu, nó có thể thay đổi để niêm phong trong tương lai mà không vi phạm tương thích. (…)

  • Hiệu suất: (…) nếu trình biên dịch JIT nhìn thấy một cuộc gọi đến một phương pháp ảo bằng cách sử dụng một loại niêm phong, trình biên dịch JIT có thể tạo ra mã hiệu quả hơn bằng cách gọi phương thức không gần như (…)

  • Tính bảo mật và khả năng dự đoán: Một lớp học phải bảo vệ trạng thái của chính nó và không cho phép chính nó trở nên bị hỏng. Khi một lớp được niêm phong, một lớp dẫn xuất có thể truy cập và thao tác nhà nước lớp cơ sở nếu bất kỳ lĩnh vực dữ liệu hoặc các phương pháp mà trong nội bộ thao tác các lĩnh vực có thể truy cập và không tin. (...)

Đó là tất cả khá tốt lý do - Tôi thực sự không nhận thức được ý nghĩa lợi ích hiệu suất cho đến khi tôi tìm kiếm nó ngay bây giờ :)

Điểm phiên bản và bảo mật có vẻ như là một lợi ích lớn về độ tin cậy mã. của dự án lớn. Nó không có drop-in cho thử nghiệm đơn vị, tất nhiên, nhưng nó sẽ giúp đỡ.

+0

FWIW: Tôi khá chắc chắn rằng HotSpot không nhận được nhiều lợi ích về hiệu suất từ ​​việc này, vì nó hỗ trợ khả năng khử sinh động động. Về cơ bản, nó giả định rằng tất cả các phương thức là không ảo cho đến khi nó thực sự tải một phiên bản khác của phương thức. Khi điều đó xảy ra, nó sẽ quay trở lại và "deoptimizes" bất kỳ nơi nào mà nó thực hiện một cuộc gọi không ảo để thay vào đó thực hiện một cuộc gọi ảo. –

+2

Phiên bản? Tôi không làm theo. Nó chỉ giống như câu nói của bạn "bạn có thể loại bỏ các 'niêm phong' tài sản từ lớp và biên dịch lại" -at không nói với lý do tại sao bạn muốn làm điều đó ở nơi đầu tiên. Hiệu suất? Hấp dẫn! Bảo mật? Các lớp con chỉ có thể truy cập vào những gì lớp cơ sở cho phép. Nếu lớp cơ sở muốn "bảo vệ" dữ liệu của nó, nó sẽ không sử dụng các thuộc tính "Được bảo vệ". Đó không phải là lý do để phong ấn cả lớp. Tôi đang thiếu nó. – ChadD

+0

Tôi nghĩ rằng phiên bản sẽ áp dụng nếu bạn phát hành một lớp "beta", có lẽ là nội bộ trong công ty của bạn. Buộc nó được niêm phong cho đến khi lớp đó đạt trạng thái "giải phóng". Bảo vệ? Lớp cơ sở công cộng với thành viên được bảo vệ, lớp dẫn xuất có dấu có thể truy cập vào thành viên, nhưng không ai khác có thể lấy được từ lớp * đó * và gây rối với thành viên. –

10

Bởi vì việc tạo kiểu cho kế thừa là công việc khó khăn hơn nhiều so với hầu hết mọi người nghĩ. Tốt nhất là đánh dấu tất cả các loại theo cách này theo mặc định vì điều này sẽ ngăn người khác kế thừa từ loại không bao giờ được dự định mở rộng.

Loại có nên được mở rộng hay không là quyết định của nhà phát triển đã tạo nó, chứ không phải nhà phát triển đến sau và muốn mở rộng nó.

+0

Điều thú vị là điều này đã được giảm giá - tôi muốn nghe phản đối về những gì tôi đã viết ở đây. –

+3

Tôi có downvoter về điều này, nhưng đừng xem xét nó một tình huống -1 :) Làm việc với mã bên thứ 3 đã bị hạn chế niêm phong có thể làm cho cuộc sống khốn khổ, đặc biệt là khi lỗi cần phải được làm việc xung quanh. Hơn một lần, tôi đã phải bọc các lớp buggy bởi vì các mức bảo vệ là không cần thiết hạn chế. – spender

+1

Lợi ích hiệu suất là lợi thế duy nhất có vẻ hợp lý với tôi. – ChadD

6

Joshua Bloch trong cuốn sách Các cuộc đàm phán Java hiệu quả về nó. Anh ta nói "tài liệu thừa kế hoặc không cho phép nó". Vấn đề là lớp học là loại hợp đồng giữa tác giả và khách hàng. Cho phép khách hàng kế thừa từ lớp cơ sở làm cho hợp đồng này nghiêm ngặt hơn nhiều. Nếu bạn sẽ kế thừa từ nó, bạn rất có thể sẽ ghi đè lên một số phương thức, nếu không bạn có thể thay thế thừa kế bằng bố cục. Phương pháp nào được phép ghi đè và những gì bạn phải thực hiện chúng - phải được ghi lại hoặc mã của bạn có thể dẫn đến kết quả không thể đoán trước. Theo như tôi nhớ, ông cho thấy ví dụ như vậy - đây là một lớp thu thập với phương pháp

public interface Collection<E> extends Iterable<E> {  
    ... 
    boolean add(E e); 
    boolean addAll(Collection<? extends E> c); 
    ... 
} 

Có một số triển khai, ví dụ: ArrayList. Bây giờ bạn muốn kế thừa từ nó và ghi đè lên một số phương thức, do đó, nó in để điều khiển một thông báo khi phần tử được thêm vào. Bây giờ, bạn có cần ghi đè cả hai số thêmaddAll hoặc chỉ thêm? Nó phụ thuộc vào cách addAll được triển khai - có hoạt động với trạng thái nội bộ trực tiếp (như ArrayList không) hoặc gọi thêm (như AbstractCollection).Hoặc có thể ở đó là addInternal, được gọi là bởi cả hai thêmaddAll. Không có câu hỏi như vậy cho đến khi bạn quyết định kế thừa từ lớp này. Nếu bạn chỉ sử dụng nó - nó không làm phiền bạn. Vì vậy, tác giả của lớp học phải ghi lại nó, nếu anh ta muốn bạn kế thừa từ lớp của mình.

Và nếu anh ta muốn thay đổi triển khai trong tương lai thì sao? Nếu lớp học của anh ta chỉ được sử dụng, không bao giờ được thừa kế, không có gì ngăn cản anh ta thay đổi việc thực hiện để hiệu quả hơn. Bây giờ, nếu bạn được kế thừa từ lớp đó, hãy xem nguồn và thấy rằng addAll gọi thêm, bạn chỉ ghi đè thêm. Sau đó tác giả thay đổi triển khai để addAll không còn gọi số thêm - chương trình của bạn bị hỏng, thư không được in khi số addAll được gọi. Hoặc bạn nhìn vào nguồn và thấy rằng addAll không gọi thêm, vì vậy bạn ghi đè thêmaddAll. Bây giờ tác giả thay đổi triển khai, do đó, addAll gọi thêm - chương trình của bạn bị hỏng một lần nữa, khi addAll được gọi là tin nhắn được in hai lần cho mỗi phần tử.

Vì vậy - nếu bạn muốn lớp học của bạn được kế thừa từ, bạn cần ghi lại cách thức. Nếu bạn nghĩ rằng bạn có thể cần phải thay đổi một cái gì đó trong tương lai có thể phá vỡ một số lớp con - bạn cần phải suy nghĩ làm thế nào để tránh nó. Bằng cách cho phép khách hàng của bạn kế thừa từ lớp của bạn, bạn sẽ tiết lộ nhiều chi tiết triển khai nội bộ hơn khi bạn chỉ cho phép họ sử dụng lớp học của bạn - bạn phơi bày quy trình làm việc nội bộ, thường có thể thay đổi trong các phiên bản sau.

Nếu bạn tiết lộ một số chi tiết và khách hàng dựa vào chúng - bạn không còn có thể thay đổi chúng. Nếu nó là ok với bạn, hoặc bạn tài liệu những gì có thể và những gì không thể được overriden - đó là tốt. Đôi khi bạn chỉ không muốn nó. Đôi khi bạn chỉ muốn nói - "chỉ sử dụng lớp này, không bao giờ kế thừa từ nó, bởi vì tôi muốn có quyền tự do thay đổi chi tiết thực hiện nội bộ".

Vì vậy, về cơ bản nhận xét "Vì lớp học không muốn có con và chúng tôi nên tôn trọng mong muốn của nó" là chính xác.

Vì vậy, ai đó muốn đánh dấu một lớp là cuối cùng/niêm phong, khi ông nghĩ rằng các thay đổi chi tiết thực hiện có thể có giá trị hơn thừa kế. Có nhiều cách khác để đạt được kết quả tương tự như thừa kế.

+0

Câu trả lời hay. Cảm ơn bạn. – Matthias

Các vấn đề liên quan