複合パターンのリーフは、リーフが使用することのない、、、およびメソッドを含むコンポーネントインターフェイスを実装しAdd
ますRemove
。GetChild
これは、インターフェイス分離の原則に違反しているようです。
では、Composite Pattern SOLIDの使用法はどうですか?
複合パターンへのリンク:http://www.dofactory.com/Patterns/PatternComposite.aspx
複合パターンのリーフは、リーフが使用することのない、、、およびメソッドを含むコンポーネントインターフェイスを実装しAdd
ますRemove
。GetChild
これは、インターフェイス分離の原則に違反しているようです。
では、Composite Pattern SOLIDの使用法はどうですか?
複合パターンへのリンク:http://www.dofactory.com/Patterns/PatternComposite.aspx
あなたのリンクとほとんどの本に描かれているパターンの本当の匂いはComponent
、Composite
. これはおそらくパターンがかなり古く、何年もそのように繰り返されてきたからだと思います. 私の見解では、 のみがComposite
合成に関連するメソッドを持つ必要があります。
私はかつてボードゲームをコンピューターゲームに変えました。遊びの駒は、六角形に分割された地球の地図上に配置されました。すべての六角形の 99% が 1 つの場所を表していました。残念ながら、いくつかの六角形には複数の場所が含まれていました。たとえば、いくつかの六角形には内部にいくつかの島がありました。これらの場所を表すために複合パターンを使用しましたが、リンクに示されているとおりではありません. それは次のようなものでした(Javaで):
public interface Location {
Set<Army> getArmies();
}
public class SingleLocation implements Location {
public Set<Army> getArmies() {
return armies ;
}
private Set<Army> armies = new HashSet<Army>();
}
public class CompositeLocation implements Location {
public Set<Army> getArmies() {
Set<Army> armies = new HashSet<Army>();
for(Location subLocation: subLocations) {
armies.addAll(subLocation.getArmies());
}
return armies;
}
public void addSubLocation(Location location) {
subLocations.add(location);
}
private Set<Location> subLocations = new HashSet<Location>();
}
のみが合成メソッドを持ち、子を持つという事実さえほとんどのクライアントに公開しないことに注意してくださいComposite
(この例では、クライアントは場所からの軍のリストのみを必要とします - それらが多くのサブ場所にあるという事実)は関係ありません)。
デザイン パターンは、正確に実装しなければならない決まったものではないことに注意してください。それらをレシピと考えてください。料理をしているときにレシピに従うときは、確かに正確に従うことができます. ただし、一部の料理人はレシピに独自のひねりを加えます。彼らは専門家であり、レシピの精神で何かを考えることなく一緒に何かを投げることができるので、他の人はそれを見さえしません. デザインパターンも同様です。それらは順応性のあるレシピです。
また、SOLID の原則を使いすぎてしまうこともあります。Robert Martin の記事を読むと、彼は、何も考えずに原則を全面的に適用すると、過度に複雑なコードが生成されると述べています。ソフトウェアは、一連のトレードオフとバランスを考慮して設計されています。単純で簡潔なコードが得られるため、純粋な SOLID を忘れることがあります。コードを完全にカプセル化、柔軟、分離などする場合、新しいプログラミング言語を発明したことになります:-)
リンクに記載されている複合パターンは、5 つのSOLID原則の 1 つであるLiskov 置換原則に違反していると言えます。
Component
Composite
には、 egに対してのみ意味のあるメソッドがありますAdd()
。Leaf
から継承するComponent
ためAdd()
、他のComponent
. ただしLeafs
、子がないため、次のメソッド呼び出しは意味のある結果を返すことができません。
myLeaf.Add( someChild );
その呼び出しは、 をスローするかMethodNotSupportedException
、返すnull
か、他の方法で に子を追加するLeaf
ことが意味をなさないことを呼び出し元に示す必要があります。
Leaf
したがって、 aを他のように扱うことはできませんComponent
。そうしようとすると例外が発生するからです。リスコフ置換原理は次のように述べています。
q(x) を、型 T のオブジェクト x について証明可能なプロパティとします。その場合、q(y) は、S が T のサブタイプである型 S のオブジェクト y に対して真でなければなりません。
Components
子を追加できるプロパティがあります。ただし、が のサブタイプでLeaf
あっても、に子を追加することはできません。これは原則に違反しています。Leaf
Component