Чи повинен клас знати про його підкласи? Чи повинен клас робити щось, що є специфічним для даного підкласу, наприклад?
Мої інстинкти говорять мені, що це погана конструкція, здається, якась антидіаграма.
Чи повинен клас знати про його підкласи? Чи повинен клас робити щось, що є специфічним для даного підкласу, наприклад?
Мої інстинкти говорять мені, що це погана конструкція, здається, якась антидіаграма.
Відповіді:
Відповідь, яку передбачає концепція класів, - «ні».
Будь-яка дія, дані або відношення, якими ви обробляєтесь, є частиною всіх підкласів - тоді слід обробляти їх у надкласі без перевірки фактичного типу. Або це стосується лише деяких підкласів - тоді вам доведеться виконувати перевірки типу виконання, щоб зробити правильну справу, суперклас повинен був би бути змінений, коли хтось із них успадковує (або він може мовчки робити неправильну справу), зміни у похідних класах можуть порушити незмінний надклас тощо.
Коротше кажучи, ви отримуєте низку поганих наслідків, які, як правило, є досить поганими, щоб відхилити такі рішення з-під руки. Якщо кілька ваших підкласів роблять те саме, і ви хочете уникнути дублювання коду (практично завжди це добре), кращим рішенням є введення класу середнього рівня, з якого всі ці підкласи можуть успадкувати код.
Він не тільки не повинен знати, він просто не може ! Зазвичай клас можна продовжити в будь-який час і в будь-якому місці. Він може бути розширений класами, які навіть не були існували під час написання.
Деякі мови дозволяють розширювати класи контролювати надклас. У Scala клас може бути позначений як sealed
, що означає, що він може бути розширений лише іншими класами в межах одного блоку компіляції (вихідний файл). Однак, якщо ці підкласи також є sealed
або final
, підкласи можуть потім бути продовжені іншими класами.
У Scala це використовується для моделювання закритих алгебраїчних типів даних, тому канонічний List
тип Haskell :
data List a = Nil | Cons a (List a)
можна моделювати в Scala так:
sealed trait List[+A]
case object Nil extends List[Nothing]
final case class Cons[+A] extends List[A]
І ви можете гарантувати, що існують лише ці два підкласи, тому що List
є sealed
і, таким чином, не можна поширюватись поза файлом, Cons
є final
і, таким чином, не може бути розширений зовсім іNil
це object
, не може бути продовжений в будь-якому випадку.
Але це конкретний випадок використання (моделювання алгебраїчних типів даних за допомогою успадкування), і навіть у цьому випадку суперклас насправді не знає про його підкласи. Це скоріше гарантія для користувача такого List
типу, що якщо він буде вчиняти дискримінацію у справі Nil
і Cons
не буде жодної іншої альтернативи, що вискакує за його спиною.
abstract internal
члена.
Проста відповідь - Ні.
Це робить код крихким і змінює два основні принципи об'єктно-орієнтованого програмування.
Так, інколи. Наприклад, коли існує обмежена кількість підкласів. шаблон відвідувача є ілюстрацією корисності цього підходу.
Приклад: вузли абстрактного синтаксичного дерева (AST) певної чітко визначеної граматики можуть бути успадковані з одного Node
класу, що реалізує шаблон відвідувача для обробки всіх типів вузлів.
Node
клас, звичайно, не містить прямих посилань на свої підкласи. Але він містить accept
метод з Visitor
параметром. І Visitor
містить visit
метод для кожного підкласу. Отже, незважаючи на те, що не Node
має прямих посилань на свої підкласи, він "знає" про них опосередковано, через Visitor
інтерфейс. Всі вони з'єдналися через це.
Якщо я напишу компонент для фірми, а пізніше, після того як я пішов, хтось продовжує його для власних цілей, чи повинен я бути проінформований про це?
Ні!
Те саме з заняттями. Довіряйте своїм інстинктам.