Hirarki paralel - sebagian sama, sebagian berbeda

12

Ada beberapa pertanyaan serupa di luar sana 1 ,2 ,3 ,4 , tetapi tampaknya bukan masalah sebenarnya dalam pertanyaan ini, juga solusinya tidak tampak optimal.

Ini adalah pertanyaan OOP umum, dengan asumsi polimorfisme, generik, dan mixin tersedia. Bahasa aktual yang digunakan adalah OOP Javascript (Typescript), tetapi masalah yang sama di Jawa atau C ++.

Saya memiliki hierarki kelas paralel, yang terkadang berbagi perilaku yang sama (antarmuka dan implementasi), tetapi kadang-kadang masing-masing memiliki perilaku 'dilindungi' sendiri. Diilustrasikan seperti ini:

3 hierarki kelas paralel, kolom tengah menunjukkan bagian umum, kolom kiri adalah hierarki kanvas dan kolom kanan menunjukkan hierarki SVG

Ini hanya untuk tujuan ilustrasi ; itu bukan diagram kelas yang sebenarnya. Untuk membacanya:

  • Apa pun di hierarki umum (tengah) dibagi antara hierarki Kanvas (kiri) dan SVG (kanan). Maksud saya adalah antarmuka dan implementasi.
  • Apa pun hanya di kolom kiri atau kanan berarti perilaku (metode dan anggota) khusus untuk hierarki itu. Sebagai contoh:
    • Baik hierarki kiri dan kanan menggunakan mekanisme validasi yang persis sama, ditampilkan sebagai metode tunggal ( Viewee.validate()) pada hierarki umum.
    • Hanya hierarki kanvas yang memiliki metode paint(). Metode ini memanggil metode cat pada semua anak.
    • Hirarki SVG perlu mengganti addChild()metode Composite, tetapi tidak demikian halnya dengan hierarki kanvas.
  • Konstruksi dari hierarki dua sisi tidak dapat dicampur. Sebuah pabrik memastikan hal itu.

Solusi I - Menggoda Warisan Terpisah

Fowler's Tease Apart Inheritance tampaknya tidak melakukan pekerjaan di sini, karena ada beberapa perbedaan antara kedua paralel.

Solusi II - Mixins

Ini adalah satu-satunya yang saat ini dapat saya pikirkan. Dua hierarki dikembangkan secara terpisah, tetapi pada setiap tingkat kelas-kelas tersebut bercampur dalam kelas umum, yang bukan bagian dari hierarki kelas. Menghilangkan structuralgarpu, akan terlihat seperti ini:

Tiga kolom lagi, kolom kiri dan kanan adalah hierarki paralel, di mana setiap kelas juga inheren dari kelas umum.  Kelas umum bukan bagian dari hierarki

Perhatikan bahwa setiap kolom akan berada dalam namespace sendiri, sehingga nama kelas tidak akan konflik.

Pertanyaan

Adakah yang bisa melihat kesalahan dengan pendekatan ini? Adakah yang bisa memikirkan solusi yang lebih baik?


Tambahan

Berikut ini beberapa contoh kode cara menggunakannya. Namespace svgdapat diganti dengan 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 );

Pada dasarnya, dalam run-time klien menyusun instance hirarki subclass Viewee; seperti itu:

Gambar yang menunjukkan hierarki objek seperti layer, rect, scroller, dll.

Katakanlah semua orang yang dilihat ini berasal dari hierarki kanvas, mereka diberikan dengan melintasi hierarki yang dapat memanggil paint()setiap orang yang dilihat. Jika mereka berasal dari hierarki svg, pengunjung yang tahu cara menambahkan diri ke DOM, tetapi tidak ada paint()traversal.

Izhaki
sumber
Rekomendasi bacaan: Review Desain: pada topik atau tidak?
Robert Harvey
Mungkin mencoba pola desain Dekorator berfitur lengkap (Erich Gamma et als, Design Patterns)?
Zon
Apa yang dilihat? Apa arti "paralel" sebagai kata benda (tidak seperti kata sifat)?
Tulains Córdova
Apakah Anda memiliki banyak warisan?
Tulains Córdova
Apakah kelas Canvas atau SVG berisi status tambahan atau data yang tidak sama? Bagaimana Anda menggunakan kelas? Bisakah Anda menunjukkan beberapa contoh kode yang menunjukkan bagaimana hiearchies ini dapat digunakan?
Euforia

Jawaban:

5

Pendekatan kedua memisahkan antarmuka dengan lebih baik, mengikuti prinsip pemisahan antarmuka.

Namun, saya akan menambahkan antarmuka Paintable.

Saya juga akan mengganti beberapa nama. Tidak perlu membuat kebingungan:

// 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 {
}
Tulains Córdova
sumber
Saya pikir Interfaces dapat membantu untuk kasus ini. Saya ingin tahu alasan mengapa jawaban Anda ditolak.
umlcat
bukan downvoter, tetapi antarmuka eksponensial IMHO bukan pola yang baik
dagnelies
@arnaud apa yang Anda maksud dengan "antarmuka eksponensial"?
Tulains Córdova
@ user61852 ... well, anggap saja itu banyak antarmuka. "eksponensial" sebenarnya adalah istilah yang salah, ini lebih seperti "multiplikatif". Dalam arti bahwa jika Anda memiliki lebih banyak "aspek" (komposit, visual, dapat dilukis ...) dan lebih banyak "elemen" (kanvas, svg ...), Anda akan berakhir dengan banyak antarmuka.
dagnelies
@arnaud Anda benar, tetapi setidaknya ada desain yang fleksibel sebelumnya dan mimpi buruk warisan OP akan terpecahkan ketika Anda tidak merasa dipaksa untuk memperpanjang. Anda memperpanjang beberapa kelas jika Anda mau dan tidak dipaksa oleh hierarki yang dibuat-buat.
Tulains Córdova
3

Ini adalah pertanyaan OOP umum, dengan asumsi polimorfisme, generik, dan mixin tersedia. Bahasa aktual yang digunakan adalah OOP Javascript (Typescript), tetapi masalah yang sama di Jawa atau C ++.

Itu sebenarnya tidak benar sama sekali. Script memiliki keunggulan substansial dibandingkan Java- yaitu, pengetikan struktural. Anda dapat melakukan sesuatu yang serupa di C ++ dengan templat yang diketik bebek, tetapi ini jauh lebih sulit.

Pada dasarnya, tentukan kelas Anda, tetapi jangan repot-repot memperluas atau mendefinisikan antarmuka apa pun. Kemudian cukup mendefinisikan antarmuka yang Anda butuhkan dan menganggapnya sebagai parameter. Kemudian, objek bisa cocok dengan antarmuka itu - mereka tidak perlu tahu untuk memperpanjangnya terlebih dahulu. Setiap fungsi dapat mendeklarasikan dengan tepat dan hanya bit-bit yang mereka berikan, dan kompiler akan memberikan Anda sebuah pass jika tipe terakhir yang memenuhi itu, meskipun kelas-kelas tidak benar-benar memperluas antarmuka tersebut secara eksplisit.

Ini membebaskan Anda dari kebutuhan untuk benar-benar mendefinisikan hierarki antarmuka dan menentukan kelas mana yang harus memperluas antarmuka mana.

Cukup tentukan setiap kelas dan lupakan tentang pengetikan antar muka-struktural akan menanganinya.

Sebagai contoh:

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());

Ini adalah naskah yang benar-benar sah. Perhatikan bahwa fungsi yang dikonsumsi tidak tahu atau tidak peduli sama sekali tentang kelas dasar atau antarmuka yang digunakan dalam definisi kelas.

Tidak masalah jika kelas terkait atau tidak berdasarkan warisan. Tidak masalah jika mereka memperluas antarmuka Anda. Cukup tentukan antarmuka sebagai parameter, dan Anda selesai - semua kelas yang memenuhi itu diterima.

DeadMG
sumber
Kedengarannya menjanjikan, tetapi saya tidak benar-benar memahami proposal (maaf, mungkin terlalu banyak bias OOP). Mungkin Anda dapat membagikan beberapa contoh kode? Sebagai contoh, baik svg.Viewee dan canvas.Viewee membutuhkan validate()metode (implementasi yang identik untuk keduanya); maka hanya svg.Viewee perlu mengganti addChild () , sementara hanya canvas.Viewee perlu mengecat () (yang memanggil paint () pada semua anak - yang merupakan anggota kelas dasar Composite ). Jadi saya tidak bisa membayangkan ini dengan pengetikan struktural.
Izhaki
Anda sedang mempertimbangkan banyak hal yang sama sekali tidak penting dalam kasus ini.
DeadMG
Jadi saya mungkin tidak mendapatkan jawaban sama sekali. Akan menyenangkan jika Anda menguraikan.
Izhaki
Saya mengedit. Intinya adalah bahwa kelas dasar benar-benar tidak relevan dan tidak ada yang peduli tentang mereka. Mereka adalah detail implementasi saja.
DeadMG
1
BAIK. Ini mulai masuk akal. A) Saya tahu apa itu mengetik bebek. B) Saya tidak yakin mengapa antarmuka sangat sentral dalam jawaban ini - pemecahan kelas adalah demi berbagi perilaku umum, Anda dapat dengan aman mengabaikan antarmuka untuk saat ini. C) Katakan dalam contoh yang Anda miliki SVGViewee.addChild(), tetapi CanvasVieweejuga perlu fitur yang persis sama. Jadi sepertinya masuk akal bagi saya bahwa keduanya melekat dari Composite?
Izhaki
3

Ikhtisar Cepat

Solusi 3: Pola Desain Perangkat Lunak "Parallel Class Hierarchy" adalah teman Anda.

Jawaban Panjang

Desain Anda MULAI BENAR. Ini dapat dioptimalkan, beberapa kelas atau anggota dapat dihapus, tetapi, ide "hierarki paralel" yang Anda terapkan untuk menyelesaikan masalah IS BENAR.

Sudah beberapa kali berurusan dengan konsep yang sama, biasanya dalam hierarki kontrol.

Setelah beberapa saat, saya BERAKHIRNYA MELAKUKAN SOLUSI SAMA DARI PEMBANGUN LAINNYA, yang kadang-kadang disebut Pola Desain "Paralel Hierarki" atau Pola Desain "Dual Hierarki".

(1) Apakah Anda pernah membagi satu kelas menjadi satu hirarki kelas?

(2) Apakah Anda pernah membagi satu kelas menjadi beberapa kelas, tanpa hierarki?

Jika Anda telah menerapkan solusi sebelumnya, secara terpisah, maka itu adalah cara untuk menyelesaikan beberapa masalah.

Tapi, bagaimana jika kita menggabungkan dua solusi ini secara bersamaan?

Gabungkan mereka, dan, Anda akan mendapatkan "Pola Desain" ini.

Penerapan

Sekarang, mari kita terapkan Pola Desain Perangkat Lunak "Parallel Class Hierarchy", untuk kasus Anda.

Saat ini Anda memiliki 2 atau lebih hierarki kelas independen, yang sangat mirip, memiliki asosiasi atau tujuan yang sama, memiliki properti atau metode yang serupa.

Anda ingin menghindari duplikasi kode atau anggota ("konsistensi"), namun, Anda tidak dapat menggabungkan kelas ini secara langsung menjadi satu, karena perbedaan di antara mereka.

Jadi, hierarki Anda sangat mirip dengan angka ini, namun, ada lebih dari satu:

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

Figure 1

Dalam hal ini, belum disertifikasi, Pola Desain, BEBERAPA HIERARCHI SIMILAR, BERGABUNG, DALAM SEBUAH TUNGGAL TUNGGAL, dan masing-masing kelas bersama atau umum diperluas dengan subklasifikasi.

Perhatikan, bahwa solusi ini rumit, karena Anda sudah berurusan dengan beberapa hierarki, oleh karena itu skenario yang kompleks.

1 Kelas Root

Di setiap hierarki ada kelas "root" bersama.

Dalam kasus Anda, ada kelas "Komposit" yang independen, untuk setiap hierarki, yang dapat memiliki beberapa properti yang serupa, dan beberapa metode yang serupa.

Beberapa anggota tersebut dapat digabung, beberapa anggota tersebut tidak dapat digabung.

Jadi, apa yang bisa dilakukan pengembang, adalah membuat kelas root base, dan mensubklasifikasikan kasus yang setara untuk setiap hierarki.

Pada Gambar 2, Anda dapat melihat diagram hanya untuk kelas ini, di mana setiap kelas, menyimpannya namespace.

Anggota, dihilangkan, sekarang.

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

Figure 2

Seperti yang Anda perhatikan, setiap kelas "Komposit" tidak lagi berada dalam hierarki yang terpisah, tetapi digabung menjadi satu hierarki bersama atau umum.

Kemudian, mari kita tambahkan anggota, mereka yang sama, dapat dipindahkan ke superclass, dan mereka yang berbeda, untuk setiap kelas dasar.

Dan seperti yang sudah Anda ketahui, metode "virtual" atau "kelebihan beban" didefinisikan dalam kelas dasar, tetapi diganti dalam subkelas. Seperti Gambar 3.

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

Figure 3

Perhatikan bahwa mungkin ada beberapa kelas tanpa anggota, dan, Anda mungkin tergoda untuk menghapus kelas-kelas itu, DONT. Mereka disebut "Kelas Hollow", "Kelas Enumeratif", dan nama lainnya.

2 Subclass

Mari kita kembali ke diagram pertama. Setiap kelas "Composite", memiliki subclass "Viewee", di setiap hierarki.

Proses ini diulang untuk setiap kelas. Catatan dari Gambar 4, kelas "Common :: Viewee" turun dari "Common :: Composite", tetapi, untuk kesederhanaan, kelas "Common :: Composite" dihilangkan, dari diagram.

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

Figure 4

Anda akan mencatat, bahwa "Canvas :: Viewee" dan "SVG :: Viewee", TIDAK LEBIH LAMA dari masing-masing "Composite", tetapi, dari "Common :: Viewee" yang umum.

Anda dapat menambahkan anggota, sekarang.

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

Figure 5

3 Ulangi Prosesnya

Proses akan berlanjut, untuk setiap kelas, "Canvas :: Visual" tidak akan turun dari "Canvas :: Viewee", buit dari "Commons :: Visual", "Canvas :: Structural" tidak akan turun dari "Canvas :: Viewee ", buit dari" Commons :: Structural ", dan sebagainya.

4 Diagram Hirarki 3D

Anda akan selesai mendapatkan semacam diagram 3D, dengan beberapa lapisan, lapisan atas, memiliki hierarki "Umum" dan lapisan bawah, memiliki setiap hierarki tambahan.

Hirarki kelas independen asli Anda, tempat sesuatu yang mirip dengan ini (Gambar 6):

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

Figure 6

Perhatikan bahwa beberapa kelas dihilangkan, dan seluruh hierarki "Kanvas" dihilangkan, untuk secara sederhana.

Hirarki kelas terintegrasi akhir mungkin sesuatu yang mirip dengan ini:

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

Perhatikan bahwa beberapa kelas dihilangkan, dan seluruh kelas "Kanvas" dihilangkan, untuk secara sederhana, tetapi, akan mirip dengan kelas "SVG".

Kelas "Biasa" dapat direpresentasikan sebagai satu lapisan diagram 3D, kelas "SVG" di lapisan lain, dan kelas "Kanvas", di lapisan ketiga.

Periksa, bahwa setiap lapisan terkait dengan yang pertama, di mana, setiap kelas memiliki kelas induk dari hierarki "Umum".

Implementasi kode mungkin perlu menggunakan salah satu, warisan antarmuka, warisan kelas, atau "mixins", tergantung pada apa yang didukung oleh Bahasa Pemrograman Anda.

Ringkasan

Seperti solusi pemrograman apa pun, jangan terburu-buru ke optimasi, optimasi sangat penting, namun, optimasi yang buruk, dapat menjadi masalah yang lebih besar, daripada masalah aslinya.

Saya tidak merekomendasikan menerapkan "Solusi 1" atau "Solusi 2".

Dalam "Solusi 1" tidak berlaku, karena, warisan, diperlukan dalam setiap kasus.

"Solusi 2", "Mixins" dapat diterapkan, tetapi, setelah mendesain kelas dan hierarki.

Mixins, adalah alternatif untuk pewarisan berbasis antarmuka, atau beberapa pewarisan berbasis kelas.

Usulan saya, Solusi 3, kadang-kadang disebut Pola Desain "Parallel Hierarchy" atau Pola Desain "Dual Hierarchy".

Banyak pengembang / desainer tidak akan setuju dengan itu, dan percaya itu seharusnya tidak ada. Tapi, saya telah menggunakan oleh diri sendiri, dan pengembang lain, sebagai solusi umum untuk masalah, seperti salah satu pertanyaan Anda.

Satu hal lagi yang hilang. Dalam solusi Anda sebelumnya, masalah utama bukanlah lebih baik menggunakan "mixin" atau "interface", tetapi, untuk memperbaiki, pertama, model kelas Anda, dan kemudian menggunakan fitur Bahasa Pemrograman yang ada.

umlcat
sumber
Terima kasih atas jawaban yang sangat teliti. Saya pikir saya mengerti itu baik-baik saja, jadi izinkan saya bertanya: canvas.vieweedan semua keturunannya memerlukan metode yang disebut paint(). Baik kelas commonmaupun tidak svgmembutuhkannya. Tetapi dalam solusi Anda, hierarki ada di common, tidak canvasatau svgseperti dalam solusi saya 2. Jadi, bagaimana tepatnya paint()berakhir di semua subkelas canvas.vieweejika tidak ada warisan di sana?
Izhaki
@Izhaki Maaf jika ada beberapa bug dalam jawaban saya. Maka paint()harus dipindahkan atau dideklarasikan di "canvas :: viewee". Gagasan pola umum tetap ada, tetapi beberapa anggota mungkin diminta untuk dipindahkan atau diubah.
umlcat
OK, jadi bagaimana subclass mendapatkannya, jika tidak ada yang berasal dari canvas::viewee?
Izhaki
Apakah Anda menggunakan alat untuk membuat seni ascii Anda? (Saya tidak yakin titik-titik itu benar-benar membantu, untuk apa nilainya.)
Aaron Hall
1

Dalam sebuah artikel berjudul Pola Desain untuk Berurusan dengan Hirarki Warisan Ganda di C ++ , Paman Bob menyajikan solusi yang disebut Stairway to Heaven . Itu menyatakan niat:

Pola ini menggambarkan jaringan hubungan pewarisan yang diperlukan ketika hierarki yang diberikan harus disesuaikan, secara keseluruhan, dengan kelas lain.

Dan diagram menyediakan:

Diagram kelas dengan dua struktur pewarisan paralel, di mana masing-masing kelas di sebelah kanan juga hampir inheren dari kelas kembarnya di sebelah kiri.  Hirarki kiri juga didasarkan sepenuhnya pada warisan virtual

Meskipun dalam solusi 2 tidak ada warisan virtual, itu sangat sesuai dengan pola Stairway to Heaven . Jadi solusi 2 tampaknya masuk akal untuk masalah ini.

Izhaki
sumber