Đây là một vấn đề tôi thường gặp phải: Hãy có một dự án cửa hàng web có lớp Sản phẩm. Tôi muốn thêm một tính năng cho phép người dùng đăng đánh giá lên sản phẩm. Vì vậy, tôi có một lớp Đánh giá tham khảo một sản phẩm. Bây giờ tôi cần một phương pháp liệt kê tất cả các đánh giá cho một sản phẩm. Có hai khả năng:
(A)
public class Product {
...
public Collection<Review> getReviews() {...}
}
(B)
public class Review {
...
static public Collection<Review> forProduct( Product product ) {...}
}
Từ việc xem mã, tôi chọn (A): Nó không tĩnh và không cần tham số. Tuy nhiên, tôi cảm thấy rằng (A) vi phạm Nguyên tắc Trách nhiệm Đơn lẻ (SRP) và Nguyên tắc Đóng mở (OCP) trong khi (B) không:
(SRP) Khi tôi muốn thay đổi cách thu thập đánh giá cho một sản phẩm, tôi phải thay đổi lớp Sản phẩm. Nhưng chỉ nên có một lý do để thay đổi lớp Sản phẩm. Và đó chắc chắn không phải là đánh giá. Nếu tôi đóng gói mọi tính năng có liên quan đến sản phẩm trong Sản phẩm, nó sẽ sớm bị hỏng.
(OCP) Tôi phải thay đổi lớp Sản phẩm để mở rộng nó với tính năng này. Tôi nghĩ rằng điều này vi phạm phần 'Đóng để thay đổi' của nguyên tắc. Trước khi tôi nhận được yêu cầu của khách hàng về việc thực hiện đánh giá, tôi đã coi Sản phẩm là hoàn thành và "đóng" nó.
Điều gì quan trọng hơn: tuân theo các nguyên tắc RẮN hoặc có giao diện đơn giản hơn?
Hay tôi đang làm gì đó sai ở đây hoàn toàn?
Kết quả
Wow, cảm ơn vì tất cả các câu trả lời tuyệt vời của bạn! Thật khó để chọn một câu trả lời chính thức.
Hãy để tôi tóm tắt các đối số chính từ các câu trả lời:
- pro (A): OCP không phải là luật và khả năng đọc mã cũng rất quan trọng.
- pro (A): mối quan hệ thực thể nên được điều hướng. Cả hai lớp có thể biết về mối quan hệ này.
- pro (A) + (B): thực hiện cả hai và ủy nhiệm trong (A) đến (B) để Sản phẩm ít có khả năng được thay đổi lại.
- pro (C): đặt các phương thức tìm kiếm vào lớp thứ ba (dịch vụ) trong đó nó không tĩnh.
- contra (B): cản trở việc chế nhạo trong các bài kiểm tra.
Một vài điều nữa trường đại học của tôi tại nơi làm việc đã đóng góp:
- pro (B): khung ORM của chúng tôi có thể tự động tạo mã cho (B).
- pro (A): vì lý do kỹ thuật của khung ORM của chúng tôi, sẽ cần phải thay đổi thực thể "đóng" trong một số trường hợp, độc lập với nơi mà người tìm thấy đi đến. Vì vậy, dù sao tôi cũng sẽ không thể bám vào RẮN.
- contra (C): to fuss ;-)
Phần kết luận
Tôi đang sử dụng cả (A) + (B) với ủy quyền cho dự án hiện tại của mình. Tuy nhiên, trong môi trường hướng dịch vụ, tôi sẽ sử dụng (C).
Assert(5 = Math.Abs(-5));
Abs()
không phải là vấn đề, kiểm tra một cái gì đó phụ thuộc vào nó là. Bạn không có đường nối để cách ly Mã kiểm tra phụ thuộc (CUT) để sử dụng giả. Điều này có nghĩa là bạn không thể kiểm tra nó như một đơn vị nguyên tử và tất cả các bài kiểm tra của bạn trở thành kiểm tra tích hợp kiểm tra logic đơn vị. Thất bại trong xét nghiệm có thể ở CUT hoặc trong Abs()
(hoặc mã phụ thuộc của nó) và loại bỏ các lợi ích chẩn đoán của các xét nghiệm đơn vị.