Mặc dù chính thức hợp pháp, điều này có thể chỉ ra mùi mã . Để tìm hiểu xem điều này có đúng như vậy trong trường hợp của bạn không, hãy tự hỏi mình ba câu hỏi:
- Bạn sẽ cần nó?
- Tại sao bạn gói nó theo cách đó?
- Làm thế nào để bạn biết nếu API gói của bạn thuận tiện để sử dụng?
Bạn sẽ cần nó?
Nếu bạn không thấy lý do để đầu tư thêm nỗ lực vào khả năng duy trì mã , hãy xem xét để nguyên như vậy. Cách tiếp cận này dựa trên nguyên tắc YAGNI
lập trình viên không nên thêm chức năng cho đến khi thấy cần thiết ... "Luôn thực hiện mọi thứ khi bạn thực sự cần chúng, không bao giờ khi bạn thấy trước rằng bạn cần chúng."
Các cân nhắc được cung cấp dưới đây cho rằng nỗ lực đầu tư vào phân tích sâu hơn là hợp lý, giả sử bạn kỳ vọng mã sẽ được duy trì lâu dài hoặc quan tâm đến việc thực hành và mài giũa kỹ năng để viết mã có thể duy trì. Nếu điều này không áp dụng, vui lòng bỏ qua phần còn lại - bởi vì bạn sẽ không cần nó .
Tại sao bạn gói nó theo cách đó?
Điều đáng chú ý đầu tiên là cả hai quy ước và hướng dẫn mã hóa chính thức đều không đưa ra bất kỳ hướng dẫn nào về điều đó, gửi tín hiệu mạnh mẽ rằng các quyết định loại này dự kiến sẽ được quyết định bởi một lập trình viên.
Nhưng nếu bạn nhìn vào thiết kế được triển khai bởi các nhà phát triển của JDK , bạn sẽ nhận thấy rằng API gói "rò rỉ" vào các gói cấp cao hơn không được thực hiện ở đó. Ví dụ, xem xét gói sử dụng đồng thời và các gói phụ của nó - khóa và nguyên tử .
- Đáng lưu ý rằng việc sử dụng API gói phụ bên trong được coi là OK, ví dụ: triển khai đồng thời nhập khẩu khóa và sử dụng ReentrantLock. Nó chỉ không lộ API khóa là công khai.
Được rồi, các nhà phát triển API cốt lõi dường như tránh điều đó và để tìm hiểu lý do tại sao nó lại tự hỏi, tại sao bạn lại đóng gói theo cách đó? Lý do tự nhiên cho điều đó là mong muốn giao tiếp với người dùng gói một số loại phân cấp, loại lớp , để gói con tương ứng với các khái niệm sử dụng mức độ thấp hơn / chuyên biệt hơn / hẹp hơn.
Điều này thường được thực hiện để làm cho API dễ sử dụng và dễ hiểu hơn, để giúp người dùng API hoạt động trong lớp cụ thể, tránh làm phiền họ với những lo ngại thuộc về các lớp khác. Nếu đây là trường hợp, việc phơi bày API cấp thấp hơn từ các gói phụ chắc chắn sẽ đi ngược lại ý định của bạn.
- Lưu ý bên cạnh, nếu bạn không thể biết tại sao bạn đóng gói theo cách này, hãy xem xét quay lại thiết kế của bạn và phân tích kỹ lưỡng cho đến khi bạn hiểu điều này. Hãy nghĩ về nó, nếu thậm chí khó giải thích với bạn, ngay cả bây giờ, sẽ khó hơn thế nào với những người sẽ duy trì và sử dụng gói của bạn trong tương lai?
Làm thế nào để bạn biết nếu API gói của bạn thuận tiện để sử dụng?
Vì thế, tôi thực sự khuyên bạn nên viết các bài kiểm tra API thực hiện được cung cấp bởi gói của bạn. Yêu cầu ai đó đánh giá cũng không gây hại, nhưng rất có thể người đánh giá API có kinh nghiệm sẽ yêu cầu bạn cung cấp các thử nghiệm như vậy. Điều đó là, thật khó để đánh bại việc xem một ví dụ sử dụng thực tế khi xem xét API.
- Người ta có thể nhìn vào lớp với một phương thức duy nhất có tham số duy nhất và mơ ước thật đơn giản , nhưng nếu thử nghiệm để yêu cầu nó tạo ra 10 đối tượng khác, gọi 20 phương thức với tổng 50 tham số, điều này phá vỡ một ảo ảnh nguy hiểm và cho thấy sự phức tạp thực sự của thiết kế.
Một lợi thế khác của việc kiểm tra là những điều này có thể đơn giản hóa rất nhiều việc đánh giá các ý tưởng khác nhau mà bạn xem xét để cải thiện thiết kế của bạn.
Đôi khi, điều đó xảy ra với tôi rằng những thay đổi triển khai tương đối nhỏ đã kích hoạt các đơn giản hóa lớn trong các thử nghiệm, giảm lượng nhập khẩu, đối tượng, yêu cầu phương thức và tham số. Ngay cả trước khi chạy thử nghiệm, điều này phục vụ một dấu hiệu tốt về cách đáng để theo đuổi hơn nữa.
Đối diện cũng xảy ra với tôi - đó là, khi những thay đổi lớn, đầy tham vọng trong việc triển khai của tôi nhằm đơn giản hóa API đã được chứng minh là sai bởi tác động nhỏ, không đáng kể trong các thử nghiệm, giúp tôi bỏ ý tưởng không hiệu quả và để lại mã như vậy (có thể chỉ là một nhận xét được thêm vào để giúp hiểu nền tảng của thiết kế và giúp người khác tìm hiểu về cách sai).
Đối với trường hợp cụ thể của bạn, điều đầu tiên bạn nghĩ đến là xem xét thay đổi kế thừa thành thành phần - nghĩa là, thay vì thực hiện SomeClass
trực tiếp Something
, bao gồm một đối tượng thực hiện giao diện đó bên trong lớp,
package me.my;
import me.my.pkg.Something;
public class SomeClass {
private Something something = new Something() {
/* ... implementation of Something goes here ... */
}
/* ... some more method implementations go here too ... */
}
Cách tiếp cận này có thể trả lại trong tương lai, ngăn ngừa rủi ro cho một số lớp con SomeClass
vô tình ghi đè lên một phương thức Something
, làm cho nó hoạt động theo cách mà bạn không có kế hoạch.