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


18

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

複数のインターフェイス継承がある場合、違いはないと思います。

編集:明確にするために、複数のクラスをサブクラス化するとSRPに違反する場合、複数の(マーカーまたは基本インターフェイス(Comparableなど))インターフェイスの実装もSRPに違反すると考えています。


明確にするために、複数のインターフェイスを実装するとSRPに違反すると思いますか

複数のクラスをサブクラス化するとSRPに違反すると、複数の(マーカーではない)インターフェースの実装もSRPに違反すると思います。
m3th0dman

私はこの質問に賛成しますが、あなたはあなたの意見を質問に埋め込んでいますが、私は同意しません。
ニコール

1
@NickC:私は意見を述べていません(上記のコメントを読んでおくべきです)。質問をより明確にするために編集します。
m3th0dman

1
@NickC私は意見を持っていません、だから私は尋ねました。2つは関連している(インターフェイスの継承とクラスの継承)とだけ言った。クラスの継承に違反すると、インターフェイスの継承にも違反します。一方に違反しない場合、他方にも違反しません。そして、私は...アップの投票を気にしない
m3th0dman

回答:


17

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

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

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

class BillingCycleInvoice : public BillingCycle, public Invoice {
};

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

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

class PersistentInvoice : public Invoice, public PersistentObject {
};

あなたのクラスは大丈夫です。技術的には、一度に2つの懸念に対応しますが、そのうちの1つだけが必須であるため、偶然の1つを「ビジネスのコスト」として引き継ぐことができます。


3
2番目の例は、アスペクト指向プログラミングの分野横断的な関心事に非常によく似ています。これは、オブジェクトがコアフォーカスではないこと(ロギング、アクセス制御テスト、永続化など)を必要とする場合があり、多重継承でそれを行えることを意味しています。それはツールの適切な使用法です。

最も簡単なのは、新しいインターフェイスを実装するためにクラスの機能を完了する必要がある場合、そうではないということです。しかし、新しい責任を追加する場合は、他のクラスとインターフェイスを実装し、依存関係として注入してもSRPに違反することはありません
Ramankingdom

9

SRPは、悪い神クラスを避けるためのガイドラインですが、文字通りあまりにも取ることができ、プロジェクトは、ほんの一握りの組み合わせなしでは実際には何もできないクラスのトンでバルーンを開始します。複数の継承/複数のインターフェースは、クラスが大きくなりすぎている兆候かもしれませんが、目の前のタスクに対して焦点が非常にきめ細かすぎて、ソリューションが過剰に設計されている兆候かもしれません。多重継承の有効なユースケースであり、あなたの心配は根拠がありません。

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


4

幾分。SRPの主な原則に注目しましょう。

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

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

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


2

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

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


2

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

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


1

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.