Швидкий огляд
Рішення 3: Шаблон дизайну програмного забезпечення «Паралельна ієрархія класів» - ваш друг.
Довгий розширений відповідь
Ваша конструкція НАЧАЛО ВПРАВО. Це може бути оптимізовано, деякі класи або члени можуть бути видалені, але ідея "паралельної ієрархії", яку ви застосовуєте для вирішення проблеми, ПРАВИЛЬНА.
Майте справу з тією ж концепцією кілька разів, як правило, в ієрархіях управління.
Через деякий час я ЗАКРИТИ РОЗВ'ЯЗУВАННЯ ІНШИХ РОЗВ’ЯЗУВАННЯ ІНШИХ РОЗВИТКІВ, які іноді називають "Шаблон дизайну" Паралельної Ієрархії "або" Дизайн подвійної Ієрархії ".
(1) Ви коли-небудь розділяли один клас на єдину ієрархію класів?
(2) Ви коли-небудь розділяли один клас на кілька класів без ієрархії?
Якщо ви застосовували ці попередні рішення окремо, то вони є способом вирішення деяких проблем.
Але що робити, якщо поєднати ці два рішення одночасно?
Поєднайте їх, і ви отримаєте цей «Дизайн-шаблон».
Впровадження
Тепер давайте застосуємо шаблон дизайну програмного забезпечення "Паралельна ієрархія класів" до вашого випадку.
На даний момент у вас є 2 або більше незалежних ієрархій класів, які дуже схожі, мають схожі асоціації або функціонування, мають схожі властивості або методи.
Ви хочете уникнути дублювання коду або членів ("узгодженість"), але ви не можете об'єднати ці класи безпосередньо в один, через відмінності між ними.
Отже, ваші ієрархії дуже схожі на цю цифру, але, проте, їх існує більше:
................................................
...............+----------------+...............
...............| Common:: |...............
...............| Composite |...............
...............+----------------+...............
...............| ... |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
...............+-------+--------+...............
...............| Common:: |...............
...............| Viewee |...............
...............+----------------+...............
...............| ... |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Common:: |........| Common:: |..
..| Visual |........| Structural |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 1
У цьому, ще не сертифікованому, Шаблон дизайну, РІЗНІ ПІДПРИЄМНІ ІЄРАРХІЇ, ПІДГОТОВЛЕННЯ, В ЄДИНУ ІЄРАРХІЮ, і кожен спільний або загальний клас розширюється за допомогою підкласифікації.
Зауважте, що це рішення є складним, оскільки ви вже маєте справу з кількома ієрархіями, тому це складний сценарій.
1 Кореневий клас
У кожній ієрархії є спільний "кореневий" клас.
У вашому випадку існує незалежний клас "Композит" для кожної ієрархії, який може мати схожі властивості та деякі подібні методи.
Деякі з цих членів можуть бути об'єднані, деякі з цих членів не можуть бути об'єднані.
Отже, те, що може зробити розробник, - це створити базовий кореневий клас та підкласити еквівалентний випадок для кожної ієрархії.
На малюнку 2 ви можете побачити схему саме для цього класу, в якій кожен клас зберігає в ньому простір імен.
Члени, поки що опущені.
................................................
...............+-------+--------+...............
...............| Common:: |...............
...............| Composite |...............
...............+----------------+...............
...............| ... |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Canvas:: |........| SVG:: |..
..| Composite |........| Composite |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 2
Як ви можете зауважити, кожен клас "Композит" вже не є окремою ієрархією, а об'єднаний в єдину спільну або загальну ієрархію.
Потім додамо членів, ті, що є однаковими, можна перемістити до надкласу, а також ті, що відрізняються, до кожного базового класу.
І як ви вже знаєте, "віртуальні" або "перевантажені" методи визначаються в базовому класі, але замінюються в підкласах. Як і малюнок 3.
................................................
.............+--------------------+.............
.............| Common:: |.............
.............| Composite |.............
.............+--------------------+.............
.............| [+] void AddChild()|.............
.............+---------+----------+.............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Canvas:: |........| SVG:: |..
..| Composite |........| Composite |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 3
Зауважте, що, можливо, є кілька класів без членів, і, можливо, ви захопите їх видалити, DONT. Їх називають «порожнисті класи», «перелічувальні класи» та інші назви.
2 Підкласи
Повернемося до першої схеми. Кожен клас "Композит" мав підклас "Viewee" у кожній ієрархії.
Процес повторюється для кожного класу. Зауважте, що, ніж на малюнку 4, клас "Загальний :: Viewee" походить від "Загального :: Композиту", але, для простоти, клас "Загальний :: Композит" виключається з діаграми.
................................................
.............+--------------------+.............
.............| Common:: |.............
.............| Viewee |.............
.............+--------------------+.............
.............| ... |.............
.............+---------+----------+.............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Canvas:: |........| SVG:: |..
..| Viewee |........| Viewee |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 4
Ви зауважите, що "Canvas :: Viewee" та "SVG :: Viewee" НЕ ДІЛЬШІ спускаються із відповідного "Composite", а із загального "Common :: Viewee".
Ви можете додати членів зараз.
......................................................
.........+------------------------------+.............
.........| Common:: |.............
.........| Viewee |.............
.........+------------------------------+.............
.........| [+] bool Validate() |.............
.........| [+] Rect GetAbsoluteBounds() |.............
.........+-------------+----------------+.............
.......................|..............................
.......................^..............................
....................../.\.............................
.....................+-+-+............................
.......................|..............................
..........+------------+----------------+.............
..........|.............................|.............
..+-------+---------+........+----------+----------+..
..| Canvas:: |........| SVG:: |..
..| Viewee |........| Viewee |..
..+-----------------+........+---------------------+..
..| |........| [+] Viewee Element |..
..+-----------------+........+---------------------+..
..| [+] void Paint()|........| [+] void addChild() |..
..+-----------------+........+---------------------+..
......................................................
Figure 5
3 Повторіть процес
Процес триватиме, для кожного класу "Canvas :: Visual" не буде сходити з "Canvas :: Viewee", а buit з "Commons :: Visual", "Canvas :: Structural" не зійде з "Canvas :: Viewee ", buit від" Commons :: Structural "тощо.
4 Діаграма 3D ієрархії
Ви закінчите отримувати своєрідну 3D-діаграму, з декількома шарами, верхній шар, має ієрархію "Загальна", а нижній - кожен додатковий ієрархій.
Ваша оригінальна ієрархія незалежних класів, де щось подібне до цього (мал. 6):
.................................................
..+-----------------+.......+-----------------+..
..| Common:: |.......| SVG:: |..
..| Composite |.......| Composite |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..| Common:: |.......| SVG:: |..
..| Viewee |.......| Viewee |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..| Common:: |.......| SVG:: |..
..| Visual |.......| Visual |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..| Common:: |.......| SVG:: |..
..| Rect |.......| Rect |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+-----------------+.......+-----------------+..
.................................................
Figure 6
Зауважте, що деякі класи опущені, а вся ієрархія "Canvas" - опущена.
Кінцева ієрархія інтегрованого класу може бути подібною до цього:
.................................................
..+-----------------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Composite |...\+..| Composite |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Viewee |...\+..| Viewee |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Visual |...\+..| Visual |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Rect |...\+..| Rect |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+-----------------+.......+-----------------+..
.................................................
Figure 7
Зауважте, що деякі класи опущені, і всі класи "Canvas" опущені, просто, але вони будуть подібні до класів "SVG".
Класи "Загальні" можуть бути представлені як один шар 3D-діаграми, класи "SVG" в іншому шарі, а "Canvas" - на третьому шарі.
Перевірте, що кожен шар пов'язаний з першим, у якому кожен клас має батьківський клас ієрархії "Загальна".
Реалізація коду може зажадати використання будь-якого, успадкування інтерфейсу, успадкування класів або "mixins", залежно від того, що підтримує ваша мова програмування.
Підсумок
Як і будь-яке рішення програмування, не поспішайте з оптимізацією, оптимізація дуже важлива, проте, погана оптимізація може стати більшою проблемою, ніж початкова проблема.
Я не рекомендую застосовувати ні "Рішення 1", ні "Рішення 2".
У "Рішення 1" це не застосовується, оскільки спадкування потрібно в кожному випадку.
"Рішення 2", "Міксин" можуть бути застосовані, але після проектування класів та ієрархій.
Міксини - це альтернатива інтерфейсу для спадкування або множинного успадкування на основі класу.
Моє запропоноване рішення 3 іноді називається шаблоном дизайну "Паралельна ієрархія" або "Дизайн подвійної ієрархії".
Багато розробників / дизайнерів не згодні з цим, і вважають, що воно не повинно існувати. Але я використовував miself та інші розробники як загальне рішення проблем, як те, що стосується вашого питання.
Ще одна відсутність. У попередніх рішеннях головна проблема полягала не в тому, щоб використовувати "mixins" або "інтерфейси", а, щоб уточнити спочатку модель своїх класів, а пізніше використовувати існуючу функцію мови програмування.