vista rápida
Solución 3: El patrón de diseño de software "Jerarquía de clases paralelas" es tu amigo.
Respuesta extendida larga
Su diseño COMENZÓ A LA DERECHA. Puede optimizarse, algunas clases o miembros pueden eliminarse, pero la idea de "jerarquía paralela" que está aplicando para resolver un problema ES CORRECTA.
Tratar con el mismo concepto varias veces, generalmente en jerarquías de control.
Después de un tiempo, TERMINÉ HACIENDO LA MISMA SOLUCIÓN QUE OTROS DESARROLLADORES, que a veces se denomina Patrón de diseño de "Jerarquía paralela" o Patrón de diseño de "Jerarquía dual".
(1) ¿Alguna vez ha dividido una sola clase en una sola jerarquía de clases?
(2) ¿Alguna vez ha dividido una sola clase en varias clases, sin una jerarquía?
Si ha aplicado estas soluciones anteriores, por separado, son una forma de resolver algunos problemas.
Pero, ¿qué pasa si combinamos estas dos soluciones, simultáneamente?
Combínalos y obtendrás este "Patrón de diseño".
Implementación
Ahora, apliquemos el patrón de diseño de software "Jerarquía de clases paralelas" a su caso.
Actualmente tiene 2 o más jerarquías de clases independientes, que son muy similares, tienen asociaciones o propósitos similares, tienen propiedades o métodos similares.
Desea evitar tener código o miembros duplicados ("coherencia"), sin embargo, no puede fusionar estas clases directamente en una sola, debido a las diferencias entre ellas.
Entonces, sus jerarquías son muy similares a esta figura, pero, sin embargo, hay más de una:
................................................
...............+----------------+...............
...............| Common:: |...............
...............| Composite |...............
...............+----------------+...............
...............| ... |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
...............+-------+--------+...............
...............| Common:: |...............
...............| Viewee |...............
...............+----------------+...............
...............| ... |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Common:: |........| Common:: |..
..| Visual |........| Structural |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 1
En este, aún no certificado, el Patrón de diseño, VARIAS JERARQUÍAS SIMILARES, SE FUSIONAN, EN UNA SOLA JERARQUÍA, y cada clase compartida o común se extiende por subclases.
Tenga en cuenta que esta solución es compleja, porque ya está lidiando con varias jerarquías, por lo tanto, es un escenario complejo.
1 La clase raíz
En cada jerarquía hay una clase "raíz" compartida.
En su caso, hay una clase "Compuesta" independiente, para cada jerarquía, que puede tener algunas propiedades similares y algunos métodos similares.
Algunos de esos miembros pueden fusionarse, algunos de esos miembros no pueden fusionarse.
Entonces, lo que puede hacer un desarrollador es crear una clase raíz base y subclasificar el caso equivalente para cada jerarquía.
En la Figura 2, puede ver un diagrama solo para esta clase, en el que cada clase mantiene su espacio de nombres.
Los miembros ya están omitidos.
................................................
...............+-------+--------+...............
...............| Common:: |...............
...............| Composite |...............
...............+----------------+...............
...............| ... |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Canvas:: |........| SVG:: |..
..| Composite |........| Composite |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 2
Como puede observar, cada clase "Compuesta" ya no se encuentra en una jerarquía separada, sino que se fusiona en una sola jerarquía compartida o común.
Luego, agreguemos los miembros, los que son iguales, se pueden mover a la superclase, y los que son diferentes, a cada clase base.
Y como ya sabe, los métodos "virtuales" o "sobrecargados" se definen en la clase base, pero se reemplazan en las subclases. Como la figura 3.
................................................
.............+--------------------+.............
.............| Common:: |.............
.............| Composite |.............
.............+--------------------+.............
.............| [+] void AddChild()|.............
.............+---------+----------+.............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Canvas:: |........| SVG:: |..
..| Composite |........| Composite |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 3
Tenga en cuenta que tal vez hay algunas clases sin miembros y que puede verse tentado a eliminar esas clases, NO. Se llaman "clases huecas", "clases enumerativas" y otros nombres.
2 Las subclases
Volvamos al primer diagrama. Cada clase "Compuesta" tenía una subclase "Viewee" en cada jerarquía.
El proceso se repite para cada clase. Tenga en cuenta que en la Figura 4, la clase "Common :: Viewee" desciende de "Common :: Composite", pero, por simplicidad, la clase "Common :: Composite" se omite del diagrama.
................................................
.............+--------------------+.............
.............| Common:: |.............
.............| Viewee |.............
.............+--------------------+.............
.............| ... |.............
.............+---------+----------+.............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Canvas:: |........| SVG:: |..
..| Viewee |........| Viewee |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 4
Notarás que "Canvas :: Viewee" y "SVG :: Viewee", NO YA NO descienden de su respectivo "Composite", sino del común "Common :: Viewee".
Puede agregar los miembros, ahora.
......................................................
.........+------------------------------+.............
.........| Common:: |.............
.........| Viewee |.............
.........+------------------------------+.............
.........| [+] bool Validate() |.............
.........| [+] Rect GetAbsoluteBounds() |.............
.........+-------------+----------------+.............
.......................|..............................
.......................^..............................
....................../.\.............................
.....................+-+-+............................
.......................|..............................
..........+------------+----------------+.............
..........|.............................|.............
..+-------+---------+........+----------+----------+..
..| Canvas:: |........| SVG:: |..
..| Viewee |........| Viewee |..
..+-----------------+........+---------------------+..
..| |........| [+] Viewee Element |..
..+-----------------+........+---------------------+..
..| [+] void Paint()|........| [+] void addChild() |..
..+-----------------+........+---------------------+..
......................................................
Figure 5
3 Repita el proceso
El proceso continuará, para cada clase, "Canvas :: Visual" no descenderá de "Canvas :: Viewee", pero desde "Commons :: Visual", "Canvas :: Structural" no descenderá de "Canvas :: Viewee ", pero desde" Commons :: Structural ", y así sucesivamente.
4 El diagrama de jerarquía 3D
Terminará de obtener una especie de diagrama 3D, con varias capas, la capa superior, tiene la jerarquía "Común" y las capas inferiores, tiene cada jerarquía adicional.
Sus jerarquías de clases independientes originales, donde algo similar a esto (Figura 6):
.................................................
..+-----------------+.......+-----------------+..
..| Common:: |.......| SVG:: |..
..| Composite |.......| Composite |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..| Common:: |.......| SVG:: |..
..| Viewee |.......| Viewee |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..| Common:: |.......| SVG:: |..
..| Visual |.......| Visual |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..| Common:: |.......| SVG:: |..
..| Rect |.......| Rect |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+-----------------+.......+-----------------+..
.................................................
Figure 6
Tenga en cuenta que algunas clases se omiten, y toda la jerarquía "Canvas" se omite, por simplicidad.
La jerarquía de clase integrada final puede ser algo similar a esto:
.................................................
..+-----------------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Composite |...\+..| Composite |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Viewee |...\+..| Viewee |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Visual |...\+..| Visual |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Rect |...\+..| Rect |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+-----------------+.......+-----------------+..
.................................................
Figure 7
Tenga en cuenta que algunas clases se omiten, y todas las clases "Canvas" se omiten, por simplicidad, pero serán similares a las clases "SVG".
Las clases "comunes" podrían representarse como una sola capa de un diagrama 3D, las clases "SVG" en otra capa y las clases "lienzo", en una tercera capa.
Verifique que cada capa esté relacionada con la primera, en la que cada clase tiene una clase padre de la jerarquía "Común".
La implementación del código puede requerir el uso de herencia de interfaz, herencia de clase o "mixins", dependiendo de lo que admita su lenguaje de programación.
Resumen
Como cualquier solución de programación, no se apresure a la optimización, la optimización es muy importante, sin embargo, una mala optimización puede convertirse en un problema mayor que el problema original.
No recomiendo aplicar "Solución 1" o "Solución 2".
En "Solución 1" no se aplica, porque, la herencia, se requiere en cada caso.
"Solución 2", "Mixins" pueden aplicarse, pero, después de diseñar las clases y las jerarquías.
Los mixins son una alternativa para la herencia basada en interfaz o la herencia múltiple basada en clases.
Mi propuesta, Solución 3, se llama a veces Patrón de diseño de "Jerarquía paralela" o Patrón de diseño de "Jerarquía dual".
Muchos desarrolladores / diseñadores no estarán de acuerdo y creen que no debería existir. Pero lo he utilizado yo mismo y otros desarrolladores como una solución común para problemas, como el de su pregunta.
Otra cosa que falta. En sus soluciones anteriores, el problema principal no era usar "mixins" o "interfaces", sino, para refinar, primero, el modelo de sus clases y luego usar una función de lenguaje de programación existente.