Ý tưởng cơ bản đằng sau OOP là dữ liệu và hành vi (dựa trên dữ liệu đó) không thể tách rời và chúng được kết hợp bởi ý tưởng về một đối tượng của một lớp. Đối tượng có dữ liệu và phương thức hoạt động với điều đó (và dữ liệu khác). Rõ ràng theo các nguyên tắc của OOP, các đối tượng chỉ là dữ liệu (như cấu trúc C) được coi là một mô hình chống.
Càng xa càng tốt.
Vấn đề là tôi đã nhận thấy rằng mã của tôi dường như ngày càng đi theo hướng chống mẫu này gần đây. Dường như với tôi rằng tôi càng cố gắng đạt được thông tin ẩn giữa các lớp và các thiết kế được ghép lỏng lẻo, các lớp của tôi càng trở nên hỗn hợp giữa dữ liệu thuần túy không có lớp hành vi và tất cả hành vi không có lớp dữ liệu.
Tôi thường thiết kế các lớp theo cách giảm thiểu nhận thức của họ về sự tồn tại của các lớp khác và giảm thiểu kiến thức của họ về các giao diện của các lớp khác. Tôi đặc biệt thực thi điều này theo kiểu từ trên xuống, các lớp cấp thấp hơn không biết về các lớp cấp cao hơn. Ví dụ:
Giả sử bạn có API trò chơi thẻ chung. Bạn có một lớp học Card
. Bây giờ Card
lớp này cần xác định tầm nhìn cho người chơi.
Một cách là có boolean isVisible(Player p)
trên Card
lớp.
Một cách khác là có boolean isVisible(Card c)
trên Player
lớp.
Tôi không thích cách tiếp cận đầu tiên cụ thể vì nó cấp kiến thức về Player
lớp cấp cao hơn cho lớp cấp thấp hơn Card
.
Thay vào đó, tôi đã chọn tùy chọn thứ ba nơi chúng tôi có một Viewport
lớp, trong đó có Player
một danh sách các thẻ xác định thẻ nào có thể nhìn thấy.
Tuy nhiên, cách tiếp cận này cướp đi cả hai Card
và Player
các lớp của một chức năng thành viên có thể. Khi bạn làm điều này cho những thứ khác hơn là tầm nhìn của thẻ, bạn là trái với Card
và Player
lớp học có chứa hoàn toàn dữ liệu như tất cả các chức năng được thực hiện trong các lớp khác, mà chủ yếu là các lớp học không có dữ liệu, chỉ cần phương pháp, giống như Viewport
ở trên.
Điều này rõ ràng chống lại ý tưởng chính của OOP.
Đó là cách chính xác? Làm thế nào tôi nên thực hiện nhiệm vụ giảm thiểu sự phụ thuộc của lớp và giảm thiểu kiến thức và khớp nối giả định, nhưng không kết thúc với thiết kế kỳ lạ trong đó tất cả các lớp cấp thấp chỉ chứa dữ liệu và các lớp cấp cao chứa tất cả các phương thức? Có ai có bất kỳ giải pháp hoặc quan điểm thứ ba về thiết kế lớp mà tránh được toàn bộ vấn đề không?
PS Đây là một ví dụ khác:
Giả sử bạn có lớp DocumentId
không thay đổi, chỉ có một BigDecimal id
thành viên duy nhất và một getter cho thành viên này. Bây giờ bạn cần phải có một phương thức ở đâu đó, DocumentId
trả về Document
id này từ cơ sở dữ liệu.
Bạn có
- Thêm
Document getDocument(SqlSession)
phương thức vàoDocumentId
lớp, đột nhiên giới thiệu kiến thức về sự kiên trì của bạn ("we're using a database and this query is used to retrieve document by id"
), API được sử dụng để truy cập DB và tương tự. Ngoài ra lớp này bây giờ yêu cầu tệp JAR kiên trì chỉ để biên dịch. - Thêm một số lớp khác với phương thức
Document getDocument(DocumentId id)
, để lạiDocumentId
lớp là chết, không có hành vi, lớp giống như cấu trúc.