Rapide vue d'ensemble
Solution 3: le modèle de conception de logiciel "Hiérarchie de classes parallèles" est votre ami.
Réponse longue et étendue
Votre conception A COMMENCÉ À DROITE. Il peut être optimisé, certaines classes ou certains membres peuvent être supprimés, mais l'idée de «hiérarchie parallèle» que vous appliquez pour résoudre un problème EST DROITE.
Traitez plusieurs fois le même concept, généralement dans les hiérarchies de contrôle.
Après un certain temps, J'AI FINI DE FAIRE LA MÊME SOLUTION QUE LES AUTRES DÉVELOPPEURS, ce qu'on appelle parfois le modèle de conception "Hiérarchie parallèle" ou le modèle de conception "Double hiérarchie".
(1) Avez-vous déjà divisé une seule classe en une seule hiérarchie de classes?
(2) Avez-vous déjà divisé une seule classe en plusieurs classes, sans hiérarchie?
Si vous avez appliqué ces solutions précédentes séparément, elles sont un moyen de résoudre certains problèmes.
Mais que se passe-t-il si nous combinons ces deux solutions simultanément?
Combinez-les et vous obtiendrez ce "modèle de conception".
la mise en oeuvre
Maintenant, appliquons le modèle de conception de logiciel "Hiérarchie de classes parallèles" à votre cas.
Vous avez actuellement 2 hiérarchies de classes indépendantes ou plus, qui sont très similaires, ont des associations ou purpouse similaires, ont des propriétés ou des méthodes similaires.
Vous souhaitez éviter d'avoir du code ou des membres en double ("cohérence"), mais vous ne pouvez pas fusionner directement ces classes en une seule, en raison des différences entre elles.
Donc, vos hiérarchies sont très similaires à ce chiffre, mais, pourtant, il y en a plus d'un:
................................................
...............+----------------+...............
...............| Common:: |...............
...............| Composite |...............
...............+----------------+...............
...............| ... |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
...............+-------+--------+...............
...............| Common:: |...............
...............| Viewee |...............
...............+----------------+...............
...............| ... |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Common:: |........| Common:: |..
..| Visual |........| Structural |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 1
Dans ce modèle de conception non encore certifié, PLUSIEURS HIÉRARCHIES SIMILAIRES SONT FUSIONNÉES, EN UNE HIERARCHIE UNIQUE, et chaque classe partagée ou commune est étendue par sous-classement.
Notez que cette solution est complexe, car vous avez déjà affaire à plusieurs hiérarchies, c'est donc un scénario complexe.
1 La classe racine
Dans chaque hiérarchie, il existe une classe "racine" partagée.
Dans votre cas, il existe une classe "Composite" indépendante, pour chaque hiérarchie, qui peut avoir des propriétés similaires et des méthodes similaires.
Certains de ces membres peuvent être fusionnés, certains de ces membres ne peuvent pas être fusionnés.
Ainsi, ce qu'un développeur peut faire, c'est de créer une classe racine de base et de sous-classer le cas équivalent pour chaque hiérarchie.
Dans la figure 2, vous pouvez voir un diagramme uniquement pour cette classe, dans lequel chaque classe conserve son espace de noms.
Les membres sont désormais omis.
................................................
...............+-------+--------+...............
...............| Common:: |...............
...............| Composite |...............
...............+----------------+...............
...............| ... |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Canvas:: |........| SVG:: |..
..| Composite |........| Composite |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 2
Comme vous pouvez le remarquer, chaque classe "Composite" n'est plus dans une hiérarchie distincte, mais fusionnée en une seule hiérarchie partagée ou commune.
Ensuite, ajoutons les membres, ceux qui sont les mêmes, peuvent être déplacés vers la superclasse, et ceux qui sont différents, dans chaque classe de base.
Et comme vous le savez déjà, les méthodes "virtuelles" ou "surchargées" sont définies dans la classe de base, mais remplacées dans les sous-classes. Comme la figure 3.
................................................
.............+--------------------+.............
.............| Common:: |.............
.............| Composite |.............
.............+--------------------+.............
.............| [+] void AddChild()|.............
.............+---------+----------+.............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Canvas:: |........| SVG:: |..
..| Composite |........| Composite |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 3
Notez qu'il existe peut-être des classes sans membres et, vous pourriez être tenté de supprimer ces classes, DONT. Ils sont appelés "classes creuses", "classes énumératives" et autres noms.
2 Les sous-classes
Revenons au premier diagramme. Chaque classe "Composite", avait une sous-classe "Viewee", dans chaque hiérarchie.
Le processus est répété pour chaque classe. Notez que la figure 4, la classe "Common :: Viewee" descend de la "Common :: Composite", mais, pour simplifier, la classe "Common :: Composite" est omise du diagramme.
................................................
.............+--------------------+.............
.............| Common:: |.............
.............| Viewee |.............
.............+--------------------+.............
.............| ... |.............
.............+---------+----------+.............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Canvas:: |........| SVG:: |..
..| Viewee |........| Viewee |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 4
Vous remarquerez que "Canvas :: Viewee" et "SVG :: Viewee", NE DESCEND PAS PLUS LONGTEMPS de leur "Composite" respectif, mais, du "Common :: Viewee" commun, à la place.
Vous pouvez maintenant ajouter les membres.
......................................................
.........+------------------------------+.............
.........| Common:: |.............
.........| Viewee |.............
.........+------------------------------+.............
.........| [+] bool Validate() |.............
.........| [+] Rect GetAbsoluteBounds() |.............
.........+-------------+----------------+.............
.......................|..............................
.......................^..............................
....................../.\.............................
.....................+-+-+............................
.......................|..............................
..........+------------+----------------+.............
..........|.............................|.............
..+-------+---------+........+----------+----------+..
..| Canvas:: |........| SVG:: |..
..| Viewee |........| Viewee |..
..+-----------------+........+---------------------+..
..| |........| [+] Viewee Element |..
..+-----------------+........+---------------------+..
..| [+] void Paint()|........| [+] void addChild() |..
..+-----------------+........+---------------------+..
......................................................
Figure 5
3 Répétez le processus
Le processus continuera, pour chaque classe, "Canvas :: Visual" ne descendra pas de "Canvas :: Viewee", buit de "Commons :: Visual", "Canvas :: Structural" ne descendra pas de "Canvas :: Viewee ", extrait de" Commons :: Structural ", et ainsi de suite.
4 Le diagramme de la hiérarchie 3D
Vous finirez d'obtenir une sorte de diagramme 3D, avec plusieurs couches, la couche supérieure, a la hiérarchie "commune" et les couches inférieures, a chaque hiérarchie supplémentaire.
Vos hiérarchies de classes indépendantes d'origine, où quelque chose de similaire à cela (figure 6):
.................................................
..+-----------------+.......+-----------------+..
..| Common:: |.......| SVG:: |..
..| Composite |.......| Composite |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..| Common:: |.......| SVG:: |..
..| Viewee |.......| Viewee |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..| Common:: |.......| SVG:: |..
..| Visual |.......| Visual |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..| Common:: |.......| SVG:: |..
..| Rect |.......| Rect |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+-----------------+.......+-----------------+..
.................................................
Figure 6
Notez que certaines classes sont omises, et toute la hiérarchie "Canvas" est omise, pour simplifier.
La hiérarchie de classe intégrée finale peut ressembler à ceci:
.................................................
..+-----------------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Composite |...\+..| Composite |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Viewee |...\+..| Viewee |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Visual |...\+..| Visual |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Rect |...\+..| Rect |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+-----------------+.......+-----------------+..
.................................................
Figure 7
Notez que certaines classes sont omises, et toutes les classes "Canvas" sont omises, pour simplifier, mais, seront similaires aux classes "SVG".
Les classes "Common" pourraient être représentées comme une seule couche d'un diagramme 3D, les classes "SVG" dans une autre couche et les classes "Canvas", dans une troisième couche.
Vérifiez que chaque couche est liée à la première, dans laquelle chaque classe a une classe parente de la hiérarchie "Common".
L'implémentation du code peut nécessiter l'utilisation de l'héritage d'interface, de l'héritage de classe ou de "mixins", selon ce que votre langage de programmation prend en charge.
Résumé
Comme toute solution de programmation, ne vous précipitez pas dans l'optimisation, l'optimisation est très importante, mais une mauvaise optimisation peut devenir un problème plus important que le problème d'origine.
Je ne recommande pas d'appliquer "Solution 1" ou "Solution 2".
Dans "Solution 1" ne s'applique pas, car l'héritage est requis dans chaque cas.
"Solution 2", "Mixins" peuvent être appliqués, mais, après la conception des classes et des hiérarchies.
Les mixins sont une alternative à l'héritage basé sur une interface ou à l'héritage multiple basé sur une classe.
Ma proposition, la Solution 3, est parfois appelée le modèle de conception "Hiérarchie parallèle" ou le modèle de conception "Hiérarchie double".
De nombreux développeurs / concepteurs ne seront pas d'accord avec cela et pensent qu'il ne devrait pas exister. Mais, j'ai utilisé par moi-même et d'autres développeurs comme une solution commune aux problèmes, comme celui de votre question.
Une autre chose manquante. Dans vos solutions précédentes, le problème principal n'était pas de savoir si utiliser des «mixins» ou des «interfaces», mais, pour affiner, d'abord, le modèle de vos classes, puis utiliser une fonctionnalité de langage de programmation existante.