Hierarchie równoległe - częściowo takie same, a częściowo różne


12

Istnieje wiele podobnych pytań 1 ,2 ,3 ,4 , ale nie wydaje się dokładnie tak w tym pytaniu, ani rozwiązania nie wydają się optymalne.

To jest ogólne pytanie OOP, przy założeniu, że polimorfizm, leki generyczne i miksy są dostępne. Rzeczywistym używanym językiem jest OOP Javascript (Typescript), ale ten sam problem występuje w Javie lub C ++.

Mam równoległe hierarchie klas, które czasem dzielą to samo zachowanie (interfejs i implementacja), ale czasami każde ma swoje „chronione” zachowanie. Zilustrowane tak:

3 równoległe hierarchie klas, środkowa kolumna pokazuje wspólne części, lewa kolumna jest hierarchią kanwy, a prawa kolumna pokazuje hierarchię SVG

Jest to wyłącznie w celach ilustracyjnych ; to nie jest rzeczywisty schemat klas. Aby to przeczytać:

  • Wszystko we wspólnej hierarchii (w środku) jest dzielone między hierarchiami Canvas (po lewej) i SVG (po prawej). Przez share rozumiem zarówno interfejs, jak i implementację.
  • Wszystko tylko w lewej lub prawej kolumnie oznacza zachowanie (metody i elementy) specyficzne dla tej hierarchii. Na przykład:
    • Zarówno lewa, jak i prawa hierarchia używają dokładnie tych samych mechanizmów sprawdzania poprawności, pokazanych jako jedna metoda ( Viewee.validate()) we wspólnej hierarchii.
    • Tylko hierarchia obszaru roboczego ma metodę paint(). Ta metoda wywołuje metodę malowania u wszystkich dzieci.
    • Hierarchia SVG musi zastąpić addChild()metodę Composite, ale nie jest tak w przypadku hierarchii obszaru roboczego.
  • Konstruktów z dwóch hierarchii bocznych nie można mieszać. Fabryka to zapewnia.

Rozwiązanie I - Tease Apart Inheritance

Wydaje się, że Fowler Tease Apart Inheritance nie wykonuje tego zadania, ponieważ istnieje pewna rozbieżność między tymi dwoma podobieństwami.

Rozwiązanie II - Mixiny

To jedyny, o którym mogę teraz myśleć. Te dwie hierarchie są opracowywane osobno, ale na każdym poziomie klasy mieszają wspólną klasę, która nie jest częścią hierarchii klas. Pominięcie structuralwidelca wygląda następująco:

Trzy kolumny ponownie, lewa i prawa kolumna są równoległymi hierarchiami, w których każda klasa jest również nieodłączna od wspólnej klasy.  Wspólne klasy nie są częścią hierarchii

Zauważ, że każda kolumna będzie miała własną przestrzeń nazw, więc nazwy klas nie będą powodować konfliktów.

Pytanie

Czy ktoś może zobaczyć błędy w tym podejściu? Czy ktoś może wymyślić lepsze rozwiązanie?


Uzupełnienie

Oto przykładowy kod, w jaki sposób należy go użyć. Przestrzeń nazw svgmożna zastąpić canvas:

var iView        = document.getElementById( 'view' ),
    iKandinsky   = new svg.Kandinsky(),
    iEpigone     = new svg.Epigone(),
    iTonyBlair   = new svg.TonyBlair( iView, iKandinsky ),
    iLayer       = new svg.Layer(),
    iZoomer      = new svg.Zoomer(),
    iFace        = new svg.Rectangle( new Rect( 20, 20, 100, 60) ),
    iEyeL        = new svg.Rectangle( new Rect( 20, 20, 20, 20) ),
    iEyeR        = new svg.Rectangle( new Rect( 60, 20, 20, 20) );

iKandinsky.setContext( iTonyBlair.canvas.getContext( '2d' ) );
iEpigone.setContext( iTonyBlair.canvas.getContext( '2d' ) );

iFace.addChildren( iEyeL, iEyeR );
iZoomer.setZoom( new Point( 2, 2 ) );
iZoomer.addChild( iFace );
iLayer.addChild( iZoomer );
iTonyBlair.setContent( iLayer );

Zasadniczo w czasie wykonywania klienci tworzą hierarchię instancji podklas Viewee; tak:

Obraz przedstawiający hierarchię obiektów, takich jak warstwa, prostokąt, scroller itp.

Powiedzmy, że wszystkie te osoby pochodzą z hierarchii obszaru roboczego, są one renderowane przez przejście przez hierarchię, która może wywoływać paint()każdego użytkownika. Jeśli pochodzą z hierarchii svg, widzowie wiedzą, jak dodać się do DOM, ale nie ma możliwości paint()przejścia.



Może wypróbujesz w pełni funkcjonalny wzór dekoratora (Erich Gamma i in., Design Patterns)?
Zon

Co to jest widz? Co oznacza „równoległy” jako rzeczownik (w przeciwieństwie do przymiotnika)?
Tulains Córdova

Czy masz wielokrotne dziedzictwo?
Tulains Córdova

Czy klasy Canvas lub SVG zawierają dodatkowy stan lub dane, które nie są wspólne? Jak korzystasz z zajęć? Czy możesz pokazać przykładowy kod pokazujący, w jaki sposób można zastosować te hierarchie?
Euforyczny

Odpowiedzi:


5

Drugie podejście lepiej segreguje interfejsy, zgodnie z zasadą segregacji interfejsów.

Dodałbym jednak interfejs do malowania.

Zmieniłbym także niektóre imiona. Nie musisz wprowadzać zamieszania:

// common

public interface IComposite {
    public void addChild(Composite e);
}

public interface IViewee extends IComposite{
    public void validate();
    public List<IBound> getAbsoluteBouns();
}

public interface IVisual {
    public List<IBound> getBounds();
}

public interface IRec {
}

public interface IPaintable {
    public void paint();
}

// canvas

public interface ICanvasViewee extends IViewee, IPaintable {
}

public interface ICanvasVisual extends IViewee, IVisual {
}

public interface ICanvasRect extends ICanvasVisual, IRec {
}


// SVG

public interface ISVGViewee extends IViewee {
    public void element();
}

public interface ISVGVisual extends IVisual, ISVGViewee {
}

public interface ISVGRect extends ISVGVisual, IRect {
}

Myślę, że interfejsy mogą pomóc w tej sprawie. Chciałbym poznać powody, dla których Twoja odpowiedź została odrzucona.
umlcat,

nie downvoter, ale interfejsy wykładnicze IMHO nie są dobrym wzorcem
diagnozy

@arnaud co rozumiesz przez „wykładnicze interfejsy”?
Tulains Córdova

@ user61852 ... cóż, powiedzmy, że to dużo interfejsów. „wykładniczy” był w rzeczywistości złym terminem, bardziej przypomina „multiplikatywny”. W tym sensie, że gdybyś miał więcej „aspektów” (kompozytowe, wizualne, do pomalowania ...) i więcej „elementów” (płótno, svg ...), miałbyś wiele interfejsów.
Dagnelies

@arnaud Masz rację, ale przynajmniej istnieje wcześniej elastyczny projekt, a koszmar spadkowy OP zostanie rozwiązany, gdy nie będziesz zmuszony do przedłużenia. Rozszerzasz klasę, jeśli chcesz i nie wymusza tego wymyślona hierarchia.
Tulains Córdova

3

To jest ogólne pytanie OOP, przy założeniu, że polimorfizm, leki generyczne i miksy są dostępne. Rzeczywistym używanym językiem jest OOP Javascript (Typescript), ale ten sam problem występuje w Javie lub C ++.

To wcale nie jest prawda. Maszynopis ma znaczącą przewagę nad Javą - mianowicie pisanie strukturalne. Możesz zrobić coś podobnego w C ++ z szablonami typu duck, ale to o wiele więcej wysiłku.

Zasadniczo zdefiniuj swoje klasy, ale nie zawracaj sobie głowy rozszerzaniem lub definiowaniem interfejsów. Następnie wystarczy zdefiniować potrzebny interfejs i przyjąć go jako parametr. Następnie obiekty mogą pasować do tego interfejsu - nie muszą wiedzieć, aby go wcześniej rozszerzyć. Każda funkcja może dokładnie zadeklarować i tylko te bity, które dają gówno, a kompilator da ci przepustkę, jeśli końcowy typ ją spełnia, nawet jeśli klasy nie rozszerzają wyraźnie tych interfejsów.

To uwalnia cię od konieczności faktycznego definiowania hierarchii interfejsów i definiowania, które klasy powinny rozszerzać, które interfejsy.

Po prostu zdefiniuj każdą klasę i zapomnij o interfejsach - zajmą się nią strukturalne typy.

Na przykład:

class SVGViewee {
    validate() { /* stuff */ }
    addChild(svg: SVG) { /* stuff */ }
}
class CanvasViewee {
    validate() { /* stuff */ }
    paint() { /* stuff */ }
}
interface SVG {
    addChild: { (svg: SVG): void };
}
f(viewee: { validate: { (): boolean }; }) {
    viewee.validate();
}
g(svg: SVG) {
    svg.addChild(svg);
}
h(canvas: { paint: { (): void }; }) {
    canvas.paint();
}
f(SVGViewee());
f(CanvasViewee());
g(SVGViewee());
h(CanvasViewee());

Jest to całkowicie uzasadniony maszynopis. Zauważ, że konsumujące funkcje nie znają ani nie gównią na temat klas podstawowych lub interfejsów używanych w definicji klas.

Nie ma znaczenia, czy klasy są powiązane, czy nie przez dziedziczenie. Nie ma znaczenia, czy rozszerzyli twój interfejs. Wystarczy zdefiniować interfejs jako parametr i gotowe - wszystkie klasy, które go spełniają, są akceptowane.


Brzmi obiecująco, ale tak naprawdę nie rozumiem tej propozycji (przepraszam, być może zbyt duże odchylenie OOP). Być może możesz udostępnić jakiś przykład kodu? Na przykład zarówno svg.Viewee , jak i canvas.Viewee potrzebują validate()metody (której implementacja jest identyczna dla obu); wtedy tylko svg.Viewee musi zastąpić metodę addChild () , a tylko canvas.Viewee potrzebuje paint () (który wywołuje paint () na wszystkich elementach potomnych - które są członkami podstawowej klasy Composite ). Więc nie mogę sobie tego wyobrazić za pomocą pisania strukturalnego.
Izhaki

Rozważasz całą masę rzeczy, które po prostu zupełnie nie mają znaczenia w tym przypadku.
DeadMG

Więc prawdopodobnie w ogóle nie otrzymałem odpowiedzi. Byłoby miło, gdybyś opracował.
Izhaki

Dokonałem edycji. Najważniejsze jest to, że klasy podstawowe są absolutnie nieistotne i nikt się nimi nie przejmuje. Są to tylko szczegóły dotyczące implementacji.
DeadMG

1
DOBRZE. To zaczyna mieć sens. A) Wiem, co to jest pisanie kaczek. B) Nie jestem pewien, dlaczego interfejsy są tak centralne w tej odpowiedzi - podział klas ma na celu dzielenie wspólnego zachowania, na razie możesz bezpiecznie zignorować interfejsy. C) Powiedz w swoim przykładzie, że masz SVGViewee.addChild(), ale CanvasVieweepotrzebujesz również dokładnie tej samej funkcji. Wydaje mi się więc, że oba są nieodłączne od Composite?
Izhaki

3

szybki przegląd

Rozwiązanie 3: Wzorzec projektowania oprogramowania „Parallel Class Hierarchy” jest Twoim przyjacielem.

Długa rozszerzona odpowiedź

Twój projekt ZACZĄŁ SIĘ PRAWO. Można go zoptymalizować, niektóre klasy lub elementy mogą zostać usunięte, ale pomysł „równoległej hierarchii”, który stosuje się w celu rozwiązania problemu, JEST PRAWIDŁOWY.

Kilka razy radziłem sobie z tą samą koncepcją, zwykle w hierarchiach kontroli.

Po pewnym czasie ZAKOŃCZYŁEM SIĘ ROBIĆ TO SAME ROZWIĄZANIE NIŻ INNI DEWELOPERZY, co nazywa się czasem Wzorem Projektu „Równoległa Hierarchia” lub Wzorem Projektu „Podwójna Hierarchia”.

(1) Czy kiedykolwiek podzieliłeś jedną klasę na jedną hierarchię klas?

(2) Czy kiedykolwiek podzieliłeś jedną klasę na kilka klas bez hierarchii?

Jeśli zastosowałeś poprzednie rozwiązania osobno, są one sposobem na rozwiązanie niektórych problemów.

Ale co, jeśli połączymy te dwa rozwiązania jednocześnie?

Połącz je, a otrzymasz „Wzorzec projektowy”.

Realizacja

Teraz zastosujmy wzorzec projektowania oprogramowania „Parallel Class Hierarchy” w twoim przypadku.

Obecnie masz 2 lub więcej niezależnych hierarchii klas, które są bardzo podobne, mają podobne powiązania lub cele, mają podobne właściwości lub metody.

Chcesz uniknąć powielania kodu lub elementów („spójności”), jednak nie możesz łączyć tych klas bezpośrednio w jedną, ze względu na różnice między nimi.

Więc twoje hierarchie są bardzo podobne do tej liczby, ale jednak istnieje więcej niż jedna:

................................................
...............+----------------+...............
...............|     Common::   |...............
...............|    Composite   |...............
...............+----------------+...............
...............|      ...       |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
...............+-------+--------+...............
...............|     Common::   |...............
...............|     Viewee     |...............
...............+----------------+...............
...............|      ...       |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..|     Common::   |........|     Common::   |..
..|     Visual     |........|   Structural   |..
..+----------------+........+----------------+..
..|      ...       |........|      ...       |..
..+----------------+........+----------------+..
................................................

Figure 1

W tym, jeszcze nie certyfikowanym, Wzorze Projektowym, KILKU PODOBNYCH HIERARCHII, SĄ POŁĄCZONE, W JEDEN HIERARCHIA, a każda wspólna lub wspólna klasa jest rozszerzana o podklasę.

Zauważ, że to rozwiązanie jest złożone, ponieważ masz już do czynienia z kilkoma hierarchiami, dlatego jest złożonym scenariuszem.

1 Klasa główna

W każdej hierarchii jest wspólna klasa „root”.

W twoim przypadku istnieje niezależna klasa „Composite” dla każdej hierarchii, która może mieć podobne właściwości i podobne metody.

Niektórych z tych członków można scalić, niektórych nie można scalić.

Zatem programista może zrobić, aby stworzyć podstawową klasę root i podklasować równoważne przypadki dla każdej hierarchii.

Na rycinie 2 możesz zobaczyć schemat tylko dla tej klasy, w którym każda klasa zachowuje przestrzeń nazw.

Członkowie są już pomijani.

................................................
...............+-------+--------+...............
...............|     Common::   |...............
...............|    Composite   |...............
...............+----------------+...............
...............|      ...       |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..|     Canvas::   |........|      SVG::     |..
..|    Composite   |........|    Composite   |..
..+----------------+........+----------------+..
..|      ...       |........|      ...       |..
..+----------------+........+----------------+..
................................................

Figure 2

Jak można zauważyć, każda klasa „Composite” nie znajduje się już w osobnej hierarchii, ale jest scalona w jedną wspólną lub wspólną hierarchię.

Następnie dodajmy członków, którzy są tacy sami, mogą zostać przeniesieni do nadklasy, a ci, którzy są inni, do każdej klasy podstawowej.

Jak już wiesz, metody „wirtualne” lub „przeciążone” są zdefiniowane w klasie podstawowej, ale zastąpione w podklasach. Jak na rysunku 3.

................................................
.............+--------------------+.............
.............|       Common::     |.............
.............|      Composite     |.............
.............+--------------------+.............
.............| [+] void AddChild()|.............
.............+---------+----------+.............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..|     Canvas::   |........|      SVG::     |..
..|    Composite   |........|    Composite   |..
..+----------------+........+----------------+..
..|      ...       |........|      ...       |..
..+----------------+........+----------------+..
................................................

Figure 3

Zauważ, że niektóre klasy mogą nie mieć członków i możesz ulec pokusie ich usunięcia, NIE DOTUJ. Nazywa się je „Pustymi klasami”, „Liczbowymi” i innymi nazwami.

2 Podklasy

Wróćmy do pierwszego schematu. Każda klasa „Composite” miała podklasę „Viewee” w każdej hierarchii.

Proces powtarza się dla każdej klasy. Uwaga niż na rysunku 4, klasa „Common :: Viewee” wywodzi się z „Common :: Composite”, ale dla uproszczenia klasa „Common :: Composite” została pominięta na schemacie.

................................................
.............+--------------------+.............
.............|       Common::     |.............
.............|       Viewee       |.............
.............+--------------------+.............
.............|        ...         |.............
.............+---------+----------+.............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..|     Canvas::   |........|      SVG::     |..
..|     Viewee     |........|     Viewee     |..
..+----------------+........+----------------+..
..|      ...       |........|      ...       |..
..+----------------+........+----------------+..
................................................

Figure 4

Zauważysz, że „Canvas :: Viewee” i „SVG :: Viewee” NIE ZNALEZI już schodzić z odpowiedniego „Composite”, ale zamiast wspólnego „Common :: Viewee”.

Możesz teraz dodać członków.

......................................................
.........+------------------------------+.............
.........|            Common::          |.............
.........|            Viewee            |.............
.........+------------------------------+.............
.........| [+] bool Validate()          |.............
.........| [+] Rect GetAbsoluteBounds() |.............
.........+-------------+----------------+.............
.......................|..............................
.......................^..............................
....................../.\.............................
.....................+-+-+............................
.......................|..............................
..........+------------+----------------+.............
..........|.............................|.............
..+-------+---------+........+----------+----------+..
..|      Canvas::   |........|         SVG::       |..
..|      Viewee     |........|        Viewee       |..
..+-----------------+........+---------------------+..
..|                 |........| [+] Viewee Element  |..
..+-----------------+........+---------------------+..
..| [+] void Paint()|........| [+] void addChild() |..
..+-----------------+........+---------------------+..
......................................................

Figure 5

3 Powtórz proces

Proces będzie kontynuowany, dla każdej klasy „Canvas :: Visual” nie zejdzie z „Canvas :: Viewee”, buit z „Commons :: Visual”, „Canvas :: Structural” nie zejdzie z „Canvas :: Viewee” ”, buit z„ Commons :: Structural ”i tak dalej.

4 Diagram hierarchii 3D

Zakończysz otrzymywanie diagramu 3D z kilkoma warstwami, górna warstwa ma hierarchię „Wspólną”, a dolna warstwa ma każdą dodatkową hierarchię.

Twoje oryginalne niezależne hierarchie klas, w których coś podobnego do tego (Rysunek 6):

.................................................
..+-----------------+.......+-----------------+..
..|      Common::   |.......|       SVG::     |..
..|     Composite   |.......|     Composite   |..
..+-----------------+.......+-----------------+..
..|       ...       |.......|       ...       |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..|      Common::   |.......|       SVG::     |..
..|      Viewee     |.......|      Viewee     |..
..+-----------------+.......+-----------------+..
..|       ...       |.......|       ...       |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..|      Common::   |.......|       SVG::     |..
..|      Visual     |.......|      Visual     |..
..+-----------------+.......+-----------------+..
..|       ...       |.......|       ...       |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..|      Common::   |.......|       SVG::     |..
..|       Rect      |.......|       Rect      |..
..+-----------------+.......+-----------------+..
..|       ...       |.......|       ...       |..
..+-----------------+.......+-----------------+..
.................................................

Figure 6

Zauważ, że niektóre klasy zostały pominięte, a cała hierarchia „Canvas” jest pominięta.

Ostateczna zintegrowana hierarchia klas może być podobna do tej:

.................................................
..+-----------------+.../+..+-----------------+..
..|      Common::   +--<.+--+       SVG::     |..
..|     Composite   |...\+..|     Composite   |..
..+-----------------+.......+-----------------+..
..|       ...       |.......|       ...       |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..|      Common::   +--<.+--+       SVG::     |..
..|      Viewee     |...\+..|      Viewee     |..
..+-----------------+.......+-----------------+..
..|       ...       |.......|       ...       |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..|      Common::   +--<.+--+       SVG::     |..
..|      Visual     |...\+..|      Visual     |..
..+-----------------+.......+-----------------+..
..|       ...       |.......|       ...       |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..|      Common::   +--<.+--+       SVG::     |..
..|       Rect      |...\+..|       Rect      |..
..+-----------------+.......+-----------------+..
..|       ...       |.......|       ...       |..
..+-----------------+.......+-----------------+..
.................................................
Figure 7

Zauważ, że niektóre klasy są pomijane, a całe klasy „Canvas” są pomijane, dla uproszczenia, ale będą podobne do klas „SVG”.

Klasy „Common” mogą być reprezentowane jako pojedyncza warstwa diagramu 3D, klasy „SVG” w innej warstwie, a klasy „Canvas” w trzeciej warstwie.

Sprawdź, czy każda warstwa jest powiązana z pierwszą, w której każda klasa ma klasę nadrzędną w hierarchii „Common”.

Implementacja kodu może wymagać użycia dziedziczenia interfejsu, dziedziczenia klas lub „miksów”, w zależności od obsługiwanego języka programowania.

streszczenie

Jak każde rozwiązanie programistyczne, nie spiesz się z optymalizacją, optymalizacja jest bardzo ważna, ale zła optymalizacja może stać się większym problemem niż problem pierwotny.

Nie zalecam stosowania „Rozwiązania 1” ani „Rozwiązania 2”.

W „Rozwiązaniu 1” nie ma zastosowania, ponieważ w każdym przypadku wymagane jest dziedziczenie.

Można zastosować „Rozwiązanie 2”, „Mixiny”, ale po zaprojektowaniu klas i hierarchii.

Mixiny stanowią alternatywę dla dziedziczenia opartego na interfejsie lub wieloskładnikowego opartego na klasach.

Moje zaproponowane rozwiązanie 3 nazywane jest czasem „Wzorem projektowym„ równoległej hierarchii ”lub„ Wzorem projektowym podwójnej hierarchii ”.

Wielu programistów / projektantów nie zgodzi się z tym i uważa, że ​​nie powinno istnieć. Ale użyłem miself i innych programistów, jako wspólnego rozwiązania problemów, takich jak jedno z twoich pytań.

Kolejna brakująca rzecz. W twoich poprzednich rozwiązaniach głównym problemem nie było użycie „miksów” lub „interfejsów”, ale udoskonalenie, po pierwsze, modelu twoich klas, a później użycia istniejącej funkcji języka programowania.


Dzięki za bardzo dokładną odpowiedź. Myślę, że dobrze to zrozumiałem, więc pozwól, że o to zapytam: canvas.vieweei wszyscy jego potomkowie potrzebują metody zwanej paint(). Ani klasy, commonani svgklasy tego nie potrzebują. Ale w roztworze, hierarchia jest w commonnie canvaslub svgtak jak w moim roztworu 2. Tak jak dokładnie paint()kończy się we wszystkich podklas canvas.viewee, jeśli nie ma tam dziedziczenia?
Izhaki,

@Izhaki Przepraszam, jeśli w mojej odpowiedzi jest kilka błędów. Następnie paint()należy przenieść lub zadeklarować w „canvas :: viewee”. Ogólna idea wzoru pozostaje, ale niektórzy członkowie mogą wymagać przeniesienia lub zmiany.
umlcat

OK, więc w jaki sposób podklasy je uzyskują, skoro żadna z nich nie pochodzi canvas::viewee?
Izhaki

Czy użyłeś narzędzia do stworzenia swojej sztuki ascii? (Nie jestem pewien, czy kropki faktycznie pomagają, jeśli chodzi o ich wartość.)
Aaron Hall,

1

W artykule zatytułowanym Wzory projektowe do radzenia sobie z hierarchiami podwójnego dziedziczenia w C ++ , wujek Bob przedstawia rozwiązanie o nazwie Stairway to Heaven . Stwierdzono zamiar:

Ten wzorzec opisuje sieć relacji dziedziczenia, która jest potrzebna, gdy daną hierarchię należy w całości zaadaptować do innej klasy.

I schemat pod warunkiem:

Schemat klasowy z dwiema równoległymi strukturami dziedziczenia, gdzie każda klasa po prawej stronie jest również praktycznie nieodłączna od swojej bliźniaczej klasy po lewej.  Lewa hierarchia jest również całkowicie oparta na wirtualnym dziedziczeniu

Chociaż w rozwiązaniu 2 nie ma wirtualnego dziedziczenia, jest ono w dużej mierze zgodne ze wzorem Stairway to Heaven . Zatem rozwiązanie 2 wydaje się uzasadnione w przypadku tego problemu.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.