Основна ідея OOP полягає в тому, що дані та поведінка (за цими даними) невіддільні і вони поєднуються з ідеєю об'єкта класу. Об'єкт має дані та методи, які працюють з цим (та іншими даними). Очевидно, що за принципами OOP об'єкти, які є лише даними (як C структури), вважаються антидіаграмою.
Все йде нормально.
Проблема в тому, що я помітив, що останнім часом мій код все більше рухається в напрямку цього антидіаграму. Мені здається, що чим більше я намагаюся домогтися інформації, що переховується між класами, і нескінченно пов'язаними конструкціями, тим більше мої класи стають сумішшю чистих даних без класів поведінки і всіх типів поведінки без класів даних.
Я, як правило, проектую класи таким чином, що мінімізує їхню обізнаність про існування інших класів і мінімізує їх знання про інтерфейси інших класів. Я особливо це застосовую в режимі зверху вниз, класи нижчого рівня не знають про класи вищого рівня. Наприклад:
Припустимо, у вас є загальний API карткової гри. У вас клас Card. Тепер цей Cardклас повинен визначити видимість для гравців.
Один із способів - це бути boolean isVisible(Player p)на Cardуроці.
Інше - мати boolean isVisible(Card c)на Playerуроці.
Мені не подобається перший підхід, оскільки він дає знання про Playerклас вищого рівня для класу нижчого рівня Card.
Натомість я вибрав третій варіант, де у нас є Viewportклас, який, з огляду на a Playerі список карток, визначає, які картки будуть видимими.
Однак такий підхід позбавляє Cardі Playerкласів можливої функції члена. Після того, як ви зробите це для інших речей, ніж видимість карт, вам залишаються Cardі Playerкласи, які містять суто дані, оскільки вся функціональність реалізована в інших класах, які в основному є класами без даних, просто методами, як Viewportвище.
Це однозначно проти головної ідеї ООП.
Який правильний шлях? Як мені вирішити завдання мінімізувати взаємозалежності класів і мінімізувати припущені знання та з'єднання, але без завершення дивного дизайну, коли всі класи низького рівня містять лише дані, а класи високого рівня містять усі методи? У когось є якесь третє рішення чи погляд на дизайн класу, який дозволяє уникнути всієї проблеми?
PS Ось ще один приклад:
Припустимо, у вас клас, DocumentIdякий є незмінним, має лише одного BigDecimal idчлена та отримувача для цього члена. Тепер потрібно десь мати метод, який дав би DocumentIdповернення Documentцього ідентифікатора з бази даних.
Чи ти:
- Додайте
Document getDocument(SqlSession)метод доDocumentIdкласу, раптом вводячи знання про вашу наполегливість ("we're using a database and this query is used to retrieve document by id"), API, що використовується для доступу до БД тощо. Також цей клас тепер вимагає збереження файлу JAR просто для компіляції. - Додайте якийсь інший клас із методом
Document getDocument(DocumentId id), залишаючиDocumentIdклас мертвим, немає поведінки, клас схожий на структуру.