web-dev-qa-db-ja.com

多重継承は単一責任原則に違反しますか?

2つの異なるクラスから継承するクラスがある場合、これは、サブクラスが自動的に(少なくとも)2つの処理を実行することを意味しますか?各スーパークラスから1つです。

複数のインターフェースを継承しても違いはないと私は思います。

編集:明確にするために、複数のクラスのサブクラス化がSRPに違反している場合、複数の(マーカー以外または基本的なインターフェース(例:比較可能))インターフェースの実装もSRPに違反していると思います。

19
m3th0dman

非常に狭い意味では、答えは「はい」です。基本クラスまたはインターフェースが単一の目的のために設計されていると仮定すると、両方を継承すると、複数の責任を持つクラスが作成されます。ただし、それが「悪いこと」であるかどうかは、継承するクラスまたはインターフェースの性質によって異なります。

クラスとインターフェイスを2つの主要なグループに分けることができます。システムの本質的な複雑さに対処するグループと、偶発的な複雑さに対処するグループです。複数の「本質的な複雑さ」のクラスから継承する場合、それは悪いことです。 1つの「必須」クラスと1つ以上の「偶発的」クラスを継承する場合は、問題ありません。

たとえば、請求システムでは、請求書と請求サイクルを表すためのクラス(本質的な複雑さに対処する)と永続オブジェクトのためのクラス(偶発的な複雑さに対処する)を持つことができます。このように継承すると

class BillingCycleInvoice : public BillingCycle, public Invoice {
};

それは悪いことです。あなたのBillingCycleInvoiceは、システムの本質的な複雑さに関係しているため、混合した責任があります。

一方、このように継承すると

class PersistentInvoice : public Invoice, public PersistentObject {
};

クラスは大丈夫です。技術的には2つの懸念事項を同時に処理しますが、重要なのは1つだけなので、偶発的なものを「ビジネスを行うためのコスト」として継承することはできません。

18
dasblinkenlight

SRPは、悪い神クラスを回避するためのガイドラインですが、文字通りに解釈することもでき、プロジェクトは、ほんの一握りで組み合わせないと実際には何もできないクラスのトンでバルーンを開始します。複数の継承/複数のインターフェースは、クラスが大きくなりすぎている兆候である可能性がありますが、フォーカスが現在のタスクに対して非常に細かすぎて、ソリューションが過度に設計されている、または単に完全である可能性もあります。多重継承の有効な使用例であり、心配は根拠のないものです。

ソフトウェア設計は科学と同じくらい芸術であり、それは多くの競合する利益のバランスをとる行為です。私たちには、問題を引き起こす一方向に遠く離れていることがわかっているものを回避するのに役立つルールがありますが、それらのルールは、最初に回避しようとしていたものと同じかそれよりも悪いまたは同じ場所に簡単に連れて行ってくれます。

9
Ryathal

幾分。 SRPの主な原則に焦点を当てましょう。

クラスの変更理由は1つだけです。

多重継承はこれを強制しませんが、それにつながる傾向があります。クラスがその基本クラスをオーバーライドまたは実装する場合は、変更する理由がそれ以上になる傾向があります。このように、インターフェースの多重継承は、クラス継承よりも厄介な傾向があります。 2つのクラスが継承されてもオーバーライドされない場合、変更の理由は新しいクラスではなく基本クラスにあります。

多重継承がSRPに違反しない場所は、基本タイプの1つを除くすべてがクラスが実装しているものではないが、クラスがたまたま持っている特性として機能する場合です。 C#のIDisposableを検討してください。使い捨てのものには2つの責任がありません。インターフェイスは、特性を共有するが明らかに責任が異なるクラスへのビューとして機能します。

4
Telastyn

私の意見ではありません。私にとって、1つの責任は「アプリケーションのユーザーをモデル化すること」です。そのデータをWebサービス経由で配信し、リレーショナルデータベースに保存する必要があるかもしれません。いくつかのミックスインクラスを継承することで、その機能を提供できます。

これは、クラスに3つの責任があるという意味ではありません。つまり、ユーザーをモデル化する責任の一部には、シリアル化と永続化のサポートが必要です。

2
kevin cline

どういたしまして。 Javaでは、ある種のドメインオブジェクト(Fooなど)を表すインターフェイスを使用できます。他のFooオブジェクトと比較する必要がある場合があるため、Comparableを実装します(比較ロジックはComparatorクラスで外部化されています)。このオブジェクトもSerializableである必要がある場合があるため、ネットワーク経由で転送できます。そしてそれはクローン可能である必要があるかもしれません。したがって、クラスは3つのインターフェースを実装しますが、Fooでサポートされているものを超えてそれらをサポートするためのロジックが内部にありません。

とはいえ、SRPを極端にするのはばかげています。クラスが複数のメソッドを定義している場合、それはSRPに違反していますか?すべてJavaオブジェクトには、toString()メソッドとequals(Object)メソッドがあります。つまり、Java内のすべてのオブジェクトが、等価と自己表現の両方を担当します。それは悪いことですか?

2
Matthew Flynn

それはあなたが責任をどう定義するかにかかっていると思います。従来のiostreamの例では、SRPに違反していません。 IOstreamは、1つの双方向ストリームを管理します。

基本的な責任を使い果たした後、より一般的な高レベルの責任に移ります。結局、主なエントリポイントの責任をどのように定義しますか?その責任は、「私のアプリが行うすべてのこと」ではなく、「主要なエントリポイントであること」でなければなりません。そうでない場合、SRPに違反してアプリケーションを作成することは不可能です。

1
stonemetal