Основна ідея 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
клас мертвим, немає поведінки, клас схожий на структуру.