クイック概要
解決策3:「Parallel Class Hierarchy」ソフトウェア設計パターンはあなたの友人です。
長い拡張回答
あなたのデザインはまさに始まりました。最適化でき、一部のクラスまたはメンバーを削除できますが、問題を解決するために適用する「並列階層」の考え方は正しいです。
通常は制御階層で、同じ概念を数回処理します。
しばらくして、「パラレル階層」デザインパターンまたは「デュアル階層」デザインパターンと呼ばれることもある他の開発者と同じソリューションを終了しました。
(1)単一のクラスを単一のクラス階層に分割したことがありますか?
(2)1つのクラスを階層なしで複数のクラスに分割したことがありますか?
これらの以前のソリューションを個別に適用した場合、それらはいくつかの問題を解決する方法です。
しかし、これら2つのソリューションを同時に組み合わせるとどうなりますか?
それらを組み合わせると、この「デザインパターン」が得られます。
実装
それでは、「並列クラス階層」ソフトウェア設計パターンをケースに適用しましょう。
現在、2つ以上のクラスの独立した階層があり、それらは非常に類似しており、類似の関連付けまたは目的、類似のプロパティまたはメソッドを持っています。
コードまたはメンバーの重複(「一貫性」)を避けたいのですが、違いがあるため、このクラスを単一のクラスに直接マージすることはできません。
したがって、階層はこの図に非常に似ていますが、それでも複数あります。
................................................
...............+----------------+...............
...............| Common:: |...............
...............| Composite |...............
...............+----------------+...............
...............| ... |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
...............+-------+--------+...............
...............| Common:: |...............
...............| Viewee |...............
...............+----------------+...............
...............| ... |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Common:: |........| Common:: |..
..| Visual |........| Structural |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 1
まだ認定されていないこの設計パターンでは、いくつかの類似した階層が単一の階層に統合され、各共有クラスまたは共通クラスはサブクラス化によって拡張されます。
すでにいくつかの階層を処理しているため、このソリューションは複雑であり、したがって複雑なシナリオであることに注意してください。
1ルートクラス
各階層には、共有された「ルート」クラスがあります。
あなたの場合、階層ごとに独立した「複合」クラスがあり、いくつかの類似したプロパティと類似したメソッドを持つことができます。
これらのメンバーの一部はマージできますが、一部のメンバーはマージできません。
したがって、開発者ができることは、基本ルートクラスを作成し、各階層のサブクラスを同等のケースにすることです。
図2では、このクラスだけの図を見ることができます。この図では、各クラスが名前空間を保持しています。
メンバーは、今では省略されています。
................................................
...............+-------+--------+...............
...............| Common:: |...............
...............| Composite |...............
...............+----------------+...............
...............| ... |...............
...............+-------+--------+...............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Canvas:: |........| SVG:: |..
..| Composite |........| Composite |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 2
お気づきかもしれませんが、各「複合」クラスは個別の階層ではなく、単一の共有または共通階層にマージされています。
次に、同じ基本クラスのメンバーをスーパークラスに移動し、異なるメンバーを各基本クラスに追加します。
そして、すでにご存じのとおり、「仮想」または「オーバーロード」メソッドは基本クラスで定義されていますが、サブクラスでは置き換えられています。図3のように。
................................................
.............+--------------------+.............
.............| Common:: |.............
.............| Composite |.............
.............+--------------------+.............
.............| [+] void AddChild()|.............
.............+---------+----------+.............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Canvas:: |........| SVG:: |..
..| Composite |........| Composite |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 3
おそらくメンバーのないクラスがいくつかあり、それらのクラスを削除したいと思われるかもしれないことに注意してください、DONT。それらは「Hollow Classes」、「Enumerative Classes」、および他の名前と呼ばれます。
2サブクラス
最初の図に戻りましょう。各「複合」クラスには、各階層に「Viewee」サブクラスがありました。
このプロセスはクラスごとに繰り返されます。図4よりも注意してください。「Common :: Viewee」クラスは「Common :: Composite」から派生していますが、簡単にするために、「Common :: Composite」クラスは図から省略されています。
................................................
.............+--------------------+.............
.............| Common:: |.............
.............| Viewee |.............
.............+--------------------+.............
.............| ... |.............
.............+---------+----------+.............
.......................|........................
.......................^........................
....................../.\.......................
.....................+-+-+......................
.......................|........................
..........+------------+------------+...........
..........|.........................|...........
..+-------+--------+........+-------+--------+..
..| Canvas:: |........| SVG:: |..
..| Viewee |........| Viewee |..
..+----------------+........+----------------+..
..| ... |........| ... |..
..+----------------+........+----------------+..
................................................
Figure 4
「Canvas :: Viewee」と「SVG :: Viewee」は、それぞれの「Composite」から派生するものではなく、共通の「Common :: Viewee」から派生するものであることに注意してください。
これで、メンバーを追加できます。
......................................................
.........+------------------------------+.............
.........| Common:: |.............
.........| Viewee |.............
.........+------------------------------+.............
.........| [+] bool Validate() |.............
.........| [+] Rect GetAbsoluteBounds() |.............
.........+-------------+----------------+.............
.......................|..............................
.......................^..............................
....................../.\.............................
.....................+-+-+............................
.......................|..............................
..........+------------+----------------+.............
..........|.............................|.............
..+-------+---------+........+----------+----------+..
..| Canvas:: |........| SVG:: |..
..| Viewee |........| Viewee |..
..+-----------------+........+---------------------+..
..| |........| [+] Viewee Element |..
..+-----------------+........+---------------------+..
..| [+] void Paint()|........| [+] void addChild() |..
..+-----------------+........+---------------------+..
......................................................
Figure 5
3プロセスを繰り返します
プロセスは継続し、各クラスで、「Canvas :: Visual」は「Canvas :: Viewee」から派生せず、buitは「Commons :: Visual」から派生し、「Canvas :: Structural」は「Canvas :: Vieweeから派生しません」 "、" Commons :: Structural "からのbuitなど。
4 3D階層図
いくつかのレイヤー、最上位レイヤーには「共通」階層、最下位レイヤーには追加の階層があります。
元の独立したクラス階層。これに似たもの(図6):
.................................................
..+-----------------+.......+-----------------+..
..| Common:: |.......| SVG:: |..
..| Composite |.......| Composite |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..| Common:: |.......| SVG:: |..
..| Viewee |.......| Viewee |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..| Common:: |.......| SVG:: |..
..| Visual |.......| Visual |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+--------+--------+..
...........|.........................|...........
...........^.........................^...........
........../.\......................./.\..........
.........+-+-+.....................+-+-+.........
...........|.........................|...........
..+--------+--------+.......+--------+--------+..
..| Common:: |.......| SVG:: |..
..| Rect |.......| Rect |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+-----------------+.......+-----------------+..
.................................................
Figure 6
いくつかのクラスは省略され、「Canvas」階層全体は省略されていることに注意してください。
最終的に統合されたクラス階層は、次のようなものになります。
.................................................
..+-----------------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Composite |...\+..| Composite |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Viewee |...\+..| Viewee |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Visual |...\+..| Visual |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+--------+--------+.......+-----------------+..
...........|.....................................
...........^.....................................
........../.\....................................
.........+-+-+...................................
...........|.....................................
..+--------+--------+.../+..+-----------------+..
..| Common:: +--<.+--+ SVG:: |..
..| Rect |...\+..| Rect |..
..+-----------------+.......+-----------------+..
..| ... |.......| ... |..
..+-----------------+.......+-----------------+..
.................................................
Figure 7
いくつかのクラスが省略され、「Canvas」クラス全体が省略されていることに注意してください。ただし、「SVG」クラスに似ています。
「共通」クラスは、3Dダイアグラムの単一レイヤー、別のレイヤーの「SVG」クラス、および3番目のレイヤーの「キャンバス」クラスとして表すことができます。
各レイヤーが最初のレイヤーに関連していることを確認します。各クラスには、「共通」階層の親クラスがあります。
コードの実装では、プログラミング言語がサポートするものに応じて、インターフェイス継承、クラス継承、または「ミックスイン」のいずれかを使用する必要があります。
概要
プログラミングソリューションとして、最適化に突入しないでください。最適化は非常に重要ですが、最適化が悪いと、元の問題よりも大きな問題になる可能性があります。
「ソリューション1」または「ソリューション2」を適用することはお勧めしません。
「ソリューション1」では、継承が必要なため、適用されません。
「Solution 2」、「Mixins」を適用できますが、クラスと階層を設計した後です。
ミックスインは、インターフェイスベースの継承、またはクラスベースの多重継承の代替手段です。
私が提案したソリューション3は、「パラレル階層」デザインパターンまたは「デュアル階層」デザインパターンと呼ばれることもあります。
多くの開発者/設計者はそれに同意せず、存在すべきではないと考えます。しかし、私は自分自身や他の開発者を、あなたの質問のような問題の一般的な解決策として使用しました。
もう一つ欠けているもの。以前のソリューションでは、主な問題は「ミックスイン」や「インターフェース」を使用することではなく、まずクラスのモデルを改良し、後で既存のプログラミング言語機能を使用することでした。