Veloce panoramica
Soluzione 3: il modello di progettazione software "Parallel Class Hierarchy" è tuo amico.
Risposta estesa estesa
Il tuo design INIZIA A DESTRA. Può essere ottimizzato, alcune classi o membri possono essere rimossi, ma l'idea di "gerarchia parallela" che stai applicando per risolvere un problema È GIUSTA.
Hanno affrontato lo stesso concetto più volte, di solito nelle gerarchie di controllo.
Dopo un po ', HO FINITO DI FARE LA STESSA SOLUZIONE DI ALTRI SVILUPPI, che a volte viene chiamato il modello di progettazione "Gerarchia parallela" o il modello di progettazione "Gerarchia doppia".
(1) Hai mai diviso una singola classe in una singola gerarchia di classi?
(2) Hai mai diviso una singola classe in più classi, senza una gerarchia?
Se hai applicato queste soluzioni precedenti, separatamente, sono un modo per risolvere alcuni problemi.
E se combinassimo queste due soluzioni contemporaneamente?
Combinali e otterrai questo "Design Pattern".
Implementazione
Ora, applichiamo il modello di progettazione software "Parallel Class Hierarchy" al tuo caso.
Al momento hai 2 o più gerarchie di classi indipendenti, che sono molto simili, hanno associazioni o scopi simili, hanno proprietà o metodi simili.
Si desidera evitare di avere codice o membri duplicati ("coerenza"), tuttavia, non è possibile unire queste classi direttamente in una singola, a causa delle differenze tra loro.
Quindi, le tue gerarchie sono molto simili a questa figura, ma, tuttavia, ce ne sono più di una:
................................................
...............+----------------+...............
...............| Common:: |...............
...............| Composite |...............
...............+----------------+...............
...............| ... |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
...............+-------+--------+...............
...............| Common:: |...............
...............| Viewee |...............
...............+----------------+...............
...............| ... |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Common:: |........| Common:: |..
..| Visual |........| Structural |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 1
In questo, non ancora certificato, Design Pattern, VARIE GERARCHIE SIMILI, VENGONO UNITE, IN UNA SINGOLA GERARCHIA, e ogni classe condivisa o comune viene estesa mediante sottoclasse.
Nota che questa soluzione è complessa, poiché hai già a che fare con diverse gerarchie, quindi è uno scenario complesso.
1 La classe principale
In ogni gerarchia c'è una classe "root" condivisa.
Nel tuo caso, esiste una classe "Composite" indipendente, per ciascuna gerarchia, che può avere proprietà simili e alcuni metodi simili.
Alcuni di questi membri possono essere uniti, altri non possono essere uniti.
Quindi, ciò che uno sviluppatore può fare è creare una classe radice di base e sottoclassare il caso equivalente per ciascuna gerarchia.
Nella Figura 2, puoi vedere un diagramma solo per questa classe, in cui ogni classe mantiene lo spazio dei nomi.
I membri, ormai, sono stati omessi.
................................................
...............+-------+--------+...............
...............| Common:: |...............
...............| Composite |...............
...............+----------------+...............
...............| ... |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Canvas:: |........| SVG:: |..
..| Composite |........| Composite |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 2
Come puoi notare, ogni classe "composita" non è più in una gerarchia separata, ma è fusa in una singola gerarchia condivisa o comune.
Quindi, aggiungiamo i membri, quelli che sono uguali, possono essere spostati nella superclasse e quelli che sono diversi, per ogni classe di base.
E come già sapete, i metodi "virtuali" o "sovraccaricati" sono definiti nella classe base, ma sostituiti nelle sottoclassi. Come in figura 3.
................................................
.............+--------------------+.............
.............| Common:: |.............
.............| Composite |.............
.............+--------------------+.............
.............| [+] void AddChild()|.............
.............+---------+----------+.............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Canvas:: |........| SVG:: |..
..| Composite |........| Composite |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 3
Nota che ci sono forse alcune classi senza membri e potresti essere tentato di rimuovere quelle classi, DONT. Sono chiamati "Classi vuote", "Classi enumerative" e altri nomi.
2 Le sottoclassi
Torniamo al primo diagramma. Ogni classe "Composite" aveva una sottoclasse "Viewee", in ciascuna gerarchia.
Il processo si ripete per ogni classe. Nota rispetto alla Figura 4, la classe "Common :: Viewee" discende dalla "Common :: Composite", ma, per semplicità, la classe "Common :: Composite" è omessa, dal diagramma.
................................................
.............+--------------------+.............
.............| Common:: |.............
.............| Viewee |.............
.............+--------------------+.............
.............| ... |.............
.............+---------+----------+.............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Canvas:: |........| SVG:: |..
..| Viewee |........| Viewee |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 4
Noterai che "Canvas :: Viewee" e "SVG :: Viewee" NON discendono più dal rispettivo "Composito", ma dal comune "Comune :: Viewee".
Puoi aggiungere i membri, ora.
......................................................
.........+------------------------------+.............
.........| Common:: |.............
.........| Viewee |.............
.........+------------------------------+.............
.........| [+] bool Validate() |.............
.........| [+] Rect GetAbsoluteBounds() |.............
.........+-------------+----------------+.............
.......................|..............................
.......................^..............................
....................../.\.............................
.....................+-+-+............................
.......................|..............................
..........+------------+----------------+.............
..........|.............................|.............
..+-------+---------+........+----------+----------+..
..| Canvas:: |........| SVG:: |..
..| Viewee |........| Viewee |..
..+-----------------+........+---------------------+..
..| |........| [+] Viewee Element |..
..+-----------------+........+---------------------+..
..| [+] void Paint()|........| [+] void addChild() |..
..+-----------------+........+---------------------+..
......................................................
Figure 5
3 Ripetere il processo
Il processo continuerà, per ogni classe, "Canvas :: Visual" non discenderà da "Canvas :: Viewee", l'acquisto da "Commons :: Visual", "Canvas :: Structural" non discenderà da "Canvas :: Viewee ", acquista da" Commons :: Structural "e così via.
4 Il diagramma della gerarchia 3D
Finirai per ottenere una sorta di diagramma 3D, con diversi livelli, il livello superiore, ha la gerarchia "Comune" e i livelli inferiori, ha ogni gerarchia aggiuntiva.
Le tue gerarchie di classi indipendenti originali, in cui qualcosa di simile a questo (Figura 6):
.................................................
..+-----------------+.......+-----------------+..
..| Common:: |.......| SVG:: |..
..| Composite |.......| Composite |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..| Common:: |.......| SVG:: |..
..| Viewee |.......| Viewee |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..| Common:: |.......| SVG:: |..
..| Visual |.......| Visual |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..| Common:: |.......| SVG:: |..
..| Rect |.......| Rect |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+-----------------+.......+-----------------+..
.................................................
Figure 6
Si noti che alcune classi vengono omesse e l'intera gerarchia "Canvas" viene omessa, per semplicità.
La gerarchia di classi integrata finale potrebbe essere simile a questa:
.................................................
..+-----------------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Composite |...\+..| Composite |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Viewee |...\+..| Viewee |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Visual |...\+..| Visual |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Rect |...\+..| Rect |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+-----------------+.......+-----------------+..
.................................................
Figure 7
Si noti che alcune classi vengono omesse e tutte le classi "Canvas" vengono omesse, in modo semplice, ma saranno simili alle classi "SVG".
Le classi "comuni" potrebbero essere rappresentate come un singolo livello di un diagramma 3D, le classi "SVG" in un altro livello e le classi "Canvas", in un terzo livello.
Controlla che ogni livello sia correlato al primo, in cui ogni classe ha una classe genitore della gerarchia "Comune".
L'implementazione del codice potrebbe richiedere l'uso di, ereditarietà dell'interfaccia, ereditarietà delle classi o "mixin", a seconda di ciò che supporta il tuo linguaggio di programmazione.
Sommario
Come qualsiasi soluzione di programmazione, non abbiate fretta nell'ottimizzazione, l'ottimizzazione è molto importante, tuttavia, una cattiva ottimizzazione, può diventare un problema più grande del problema originale.
Non consiglio di applicare "Soluzione 1" o "Soluzione 2".
In "Soluzione 1" non si applica, perché, l'eredità, è richiesta in ciascun caso.
"Soluzione 2", "Mixin" possono essere applicati, ma, dopo aver progettato le classi e le gerarchie.
I mixin sono un'alternativa all'ereditarietà basata su interfaccia o ereditarietà multipla basata su classi.
La mia proposta, Soluzione 3, viene talvolta definita come modello di progettazione "Gerarchia parallela" o modello di progettazione "Gerarchia doppia".
Molti sviluppatori / designer non sono d'accordo e credono che non dovrebbe esistere. Ma ho usato me stesso e altri sviluppatori come una soluzione comune ai problemi, come quella della tua domanda.
Un'altra cosa mancante. Nelle tue soluzioni precedenti, il problema principale non era quello di utilizzare "mixin" o "interfacce", ma, per prima cosa, di affinare il modello delle tue classi e successivamente utilizzare una funzionalità del linguaggio di programmazione esistente.