Дизайн: Відкликання до батьківського класу


13

При моделюванні предмета з дітьми зазвичай включають дітей за складом як члена батьківського класу. Однак іноді діти повинні щось сказати батькові, вони повинні викликати функцію батька. Як це можна досягти за допомогою C ++? Деякі варіанти:

  1. Зробіть батьківський клас глобальним, тому дочірні об’єкти зможуть викликати членські функції батьківського об'єкта.

  2. Введіть батьківський об'єкт у вигляді вказівника чи посилання в кожен дочірній об’єкт. Тоді, коли дитині потрібно щось сказати батьківському об'єкту, він завжди може це зробити, оскільки він має змінну члена, яку він може використовувати.

Які ще методи цього робити? Чи є загальна модель дизайну чи назва цього виду?

Зауважте, що мене цікавлять ідеї та рішення C ++, оскільки деталі будуть відрізнятися в інших об'єктно-орієнтованих мовах. Наприклад, точка 2 вище згадує "покажчики або посилання", і обидва можливі лише в C ++. C ++ має мовні особливості, яких немає в інших мовах, тому реалізація рішення проблеми потенційно може включати ці мовні функції, роблячи рішення відмінним від того, що хтось може придумати іншою мовою.


ви можете додати приклад? Це вагомий приклад для вашого питання? У вас є orderobject (= батько) з orderitems (діти) і хочете оновити загальну кількість замовлень при зміні кількості замовлення? чи думаєте про щось зовсім інше?
k3b

@ k3b Так, це вірний приклад. Деяка інформація у дитини змінилася, вимагаючи від батьків щось робити.
сашанг

просто додайте деякі параметри конструктора та довідкові члени даних до кожного дочірнього класу.
tp1

Чи потрібно дитині знати все про батька, чи буде достатньо простого delegate?
Жульєн Герто

Відповіді:


16

Перш за все, це може бути кодовий запах. Сенс використання композиції для батьків / дітей полягає в тому, що батько знає про дітей, але не навпаки. Особливо, якщо відношення більше "містить", ніж "складається".

Посилання на батьків є можливим і досить поширеним у C ++. В інших мовах функціональний об’єкт або подія частіше використовується, щоб дозволити дитині спілкуватися з речами, які, можливо, захочуть знати сторонні люди. Це звичайний зразок публікації-підписника. Я підозрюю, що більш ідіоматичне залежить від того, яку версію C ++ ви використовуєте та стандарти вашої кодової бази.


У моїй ситуації це кодовий запах. Чудова відповідь.
Мартін Пфеффер

3

Як зазначали інші, основна ідея введення батьківського об'єкта як вказівника або опорного шляху - це в принципі.

У цього є один недолік: ви отримуєте циклічну залежність між батьком і дитиною. Якщо ви хочете цього уникнути, визначте абстрактний базовий клас (інтерфейс), IParentвід якого наслідує ваш батько. IParentповинні містити методи як віртуальні функції, які дитина хоче викликати. Потім введіть батьків як посилання на IParent. Це набагато полегшує тестування одиниці дитини, оскільки тепер ви можете легко замінити батьківський об'єкт макетом.

Якщо вашій дитині потрібно викликати лише одну функцію вашого батьківського об'єкта, повний IParentклас може бути завеликим. У цьому випадку буде достатньо ввести вказівник на функцію-члена або дитину або об'єкт функтора, який інкапсулює цю функцію-члена.


2

Що ви можете зробити, це зберегти посилання на батьків у дочірньому класі за складом. Таким чином, дитина знає свого батька і може застосовувати до нього публічні методи.

Тож я б пішов з варіантом 2. Ти повинен бути обережним, хоча, коли дитина видаляється з батьків, потрібно видалити посилання на батьків у дитини та вказати його на нульове значення (або на нового батька, якщо він має один). Або ви можете просто видалити дочірній об’єкт, залежно від контексту.


1

Передайте їм посилання або вказівник на батьків. Ви можете зробити їх друзями з батьків або оприлюднити названий метод. Якщо ви не хочете робити нічого з вищезазначеного, ви можете передати їм об'єкт "міст", який відкриває один із батьківських методів як загальнодоступний і сам є приватним вкладеним класом батьків (тому він має доступ до кожного батьківського методу ). Однак це може бути занадто складно у багатьох ситуаціях.


1

2) Введіть батьківський об'єкт у вигляді вказівника чи опорного пункту в кожен дочірній об’єкт. Тоді, коли дитині потрібно щось сказати батьківському об'єкту, він завжди може це зробити, оскільки він має змінну члена, яку він може використовувати.

Це абсолютно життєздатний варіант. Усі сучасні мови мають функцію, яку можна використовувати для позначення іншої мови.


1

Існує подібний підхід з незначними варіаціями, але який дає переваги:

Скажімо, батько A містить компонент C.

У Компоненті C оголосіть InterfaceC та посилайтеся на нього. Це інтерфейс компонента із зовнішнім світом.

Батько A реалізує InterfaceC і встановлює його посилання на Компонент C. Компонент C бачить батьківський A як InterfaceC.

Ідея така: компонент спілкується з зовнішньою стороною за допомогою свого інтерфейсу.

Переваги використання цього над встановленням батька безпосередньо:

Скажіть, що компонент щось робить, і про це потрібно повідомити батьків. Він викликає інтерфейс. Пізніше ви вирішите, що хочете змінити батьківську. Компонент зовсім не хвилює, і ви не зробите в ньому жодних змін.

Скажіть пізніше, що ви хочете повідомити про багато об’єктів про подію. Ви просто створите список InterfaceC і додаєте до нього посилання.

Недоліки: батьківський клас в кінцевому підсумку реалізує багато інтерфейсів (я вважаю це перевагою, хоча, дивлячись на декларацію класу, я одразу знаю, хто з ним розмовляє)


0

Зауважте, це специфічно c #. Я не знаю, чи є у c ++ щось подібне.

Якщо у вас є форма gui з кнопковими кнопками, ви зазвичай маєте інший підхід, використовуючи Event-Subscribtion, також відомий як Observer_pattern або Publish – Subscribe .

Кнопка звичайно не знає конкретної форми, де вона живе. Натомість кнопка запускає або публікує подію, і форма отримує підписане повідомлення і може відповідно реагувати.

Крім механізмів, цей механізм може бути використаний у всіх стосунках батьків і дитини

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.