例1:
基本クラスA
があると仮定します。クラスB
はクラスA
を拡張します(クラスB
は派生クラスです)。
結論として、クラスB
は継承の概念を使用しているため、単一責任の原則に従いませんか?つまり、クラスA
に特定の変更が加えられると、クラスB
にも変更が必要になりますか?したがって、これらの変更の責任はClass A
とClass B
の間で共有されますか?
例2:
class Monitorable_stack extends Stack {
private int high_water_mark = 0;
private int current_size;
public void Push( Object article )
{ if( ++current_size > high_water_mark )
high_water_mark = current_size; super.Push(article);
}
public Object pop()
{
--current_size;
return super.pop();
}
public int maximum_size_so_far()
{
return high_water_mark;
}
}
SOLID原則はこのコードに準拠しており、SOLID原則をよりよく理解するためにいくつかの団体が私を助けることができますか?
ボブおじさんの単一責任原則に関する記事 原則の発明者は次のように説明しています:
SRPは、各ソフトウェアモジュールに変更する理由が1つだけあることを意味します。
しかし、彼の説明では、「理由」は非常にあいまいであり、客観的な技術要素よりも意思決定に関連していることをすぐに理解できます。
この原則は人に関するものです。
したがって、原則の全体的な表現は完全に誤解を招くものです。幸いにも、彼は別の言い回しを提供します:
同じ理由で変化するものをまとめます。 さまざまな理由で変化するものを分離します。
そしてここですべてが明らかになります:A
に一般的なAの概念に関連するすべて(たとえば、Vehicle
、Stack
)、およびB
に関連するすべてを集めますAの特殊化(例:Car
、a MonitoredStack
)。責任を混在させないでください(たとえば、Stack
での監視に関連しない一般的なMonitoredStack
の動作を変更しないでください。Stack
基本クラスで監視の問題を引き起こさないでください)。
したがって、継承は、適切に行われた場合、SRPに違反しません。 Bの変更でAの変更が必要な場合にのみ、SRPに違反します。
最後に、継承がSRPに反する場合、SOLIDは存在しません。継承が[〜#〜] o [〜#〜](開く/閉じる)そして、[〜#〜] s [〜#〜]と矛盾します。
不必要な密結合を簡単に作成できるため、継承は実際に問題になる可能性があります。それらは必ずしも悪いわけではありませんが、同じことが作曲で達成できるかどうか常に検討する必要があります。
たとえば、あなたの例では、責任は実際にはかなりよく分離されているように見えます。 Monitorable_stack
の実装は、スタックの内部には結合されていません。ただし、これは、最初から継承を使用する必要がないことも意味します。 Monitorable_stack
は、stack
をラップして同じインターフェースを提供するが、stack
から継承しないアダプターである可能性があります。これにより、内部への結合のリスクを回避できますが、定型コードが増える代わりに、パブリックインターフェイスのすべてのメソッドを基になるstack
に委任する必要がありますが、継承では必要なものだけをオーバーライドできます変更する。
stack
に非公開のcurrent_size
があり、それを保持する代わりにmonitorable_stack
が観察した場合、カップリングのより悪い形式になります。その後、stack
の実装がこのカウンタを使用しないように変更された場合、monitorable_stack
は(おそらく他のサブクラスも)壊れます。 SOLIDには、このような問題を回避するためのオープン/クローズドの原則がありますが、最初からカップリングを回避することをお勧めします。
単一責任の原則は紛らわしい名前が付けられ、誤解されることが多いため、懸念の結合と分離について話したいと思います。
数年間、単一責任の原則を適用しようとするのを待ちます。学習者として、あなたは必然的にそれを完全に間違ったものにするでしょう。
継承を使用するなど、かなり合理的なことをしたいが、SRPを理由にすべきではないと思うときはいつでも、SRPを間違って理解している可能性が高いです。
この場合、スタックの実装を変更してもサブクラスには影響しません。 Stackのインターフェースを変更するとeveryoneに影響するため、サブクラスは他のコードと同じ状況になります。 SRPとは関係ありません。
結論として言えば、クラスBは継承の概念を使用しているため、単一責任の原則に従いません。
いいえ。SRPは、単一の責任を持つ各クラスに焦点を合わせています。 FooRepository
はFoo
オブジェクトを取得する方法を知っていますが、たとえば探しているオブジェクトが見つからない場合にメッセージを記録する方法の具体的な実装の詳細を知っている。その二次的な責任は、実際には別のクラスの(唯一の)責任でなければなりません。 Logger
。すべてのクラスはone事を行う方法を知っています、そしてそれがSRPが規定するものです。クラスには1つの責任があり、複数のことを実行する必要がある場合は、他のクラスへの依存関係(それぞれが1つの責任を持つ)があります。
SRPは、反転した、つまり2つのクラスが同様の(ただし、何らかの点で異なる)責任を負うことに重点を置きません。あなたが考えているのはDRY(Do n't Repeat Yourself))で、不要なコードの繰り返しに焦点を当てています。
これら2つの類似しているが異なるクラスは通常、DRYに違反しますが、SRPに違反しません。そして、それは無視)これらの2つのクラスには、共通の祖先があるかどうかがあります。
つまり、クラスAに特定の変更が発生すると、クラスBにも変更が必要になりますか?
これは、継承が機能するための方法ではありません。クリーンなコードベースでは、Bへの変更を必要とするAへの唯一の変更は、Aのcontractへの変更です。そのような変更の結果(つまり、Bを変更する必要がある)は避けられません。 SRPに関係なく。
Aの非契約変更によりBを変更する必要がある場合は、継承を適切に(または完全に)実装していません。継承された階層でも、各クラスには独自の責任があります。これらは機能レベルで密接に関連していますが、実際には重複していません。継承の全体的なポイントは、(そうでなければ結合された)クラスの責任を2つの個別チャンクに分割することです。
したがって、これらの変更の責任はクラスAとクラスBの間で共有されますか?
「変更に対する責任」は概念ではなく、SRPに関するものではありません。
パブリック契約を変更すると、常に(おそらく)消費者によるこの契約の使用法を変更する必要があります。これは、契約が正確に何であるかを定義すると、論理的で避けられない事実です。
SOLID原則はこのコードに準拠しており、SOLID原則をよりよく理解するためにいくつかの団体が私を助けることができますか?
これは、スニペットに基づいて実際に答えることはできません。