Ý 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ờ Cardlớ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 Cardlớp.
Một cách khác là có boolean isVisible(Card c)trên Playerlớ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ề Playerlớ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 Viewportlớp, trong đó có Playermộ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 Cardvà Playercá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 Cardvà Playerlớ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 DocumentIdkhông thay đổi, chỉ có một BigDecimal idthà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 đó, DocumentIdtrả về Documentid này từ cơ sở dữ liệu.
Bạn có
- Thêm
Document getDocument(SqlSession)phương thức vàoDocumentIdlớ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ạiDocumentIdlớp là chết, không có hành vi, lớp giống như cấu trúc.