web-dev-qa-db-ja.com

単一責任原則の例は何ですか?

誰かが単一責任原則の例を教えてくれますか?実際には、クラスが単一の責任を持つことが何を意味するのかを理解しようとしています。毎日このルールを破るのではないかと心配です。

34
Sachin Kainth

固体の説明 を確認してください。

もっと具体的なことを求めない限り、もっと手助けするのは難しいでしょう。

単一の責任は、クラスが1つの特定のこと(責任)を実行し、必要以上のことを実行しないことを意味します。これは、高凝集性とも呼ばれます。

クラスはしばしば低凝集度で始まることはありませんが、通常、いくつかのリリースとさまざまな開発者が追加した後、突然、それがモンスターまたは神のクラスになったことに気づくでしょう。したがって、クラスはリファクタリングする必要があります。

良い例を考えるのは難しいですが、最近考えることができるのは、さまざまなパケット処理ステージを管理するクラスで、Chain of Responsibilityのタイプです。このクラスの最初の目的は、ステージのリストを維持し、それらの呼び出しのpacketProcess()を調整することでした。結局のところ、(マネージャークラスはステージに簡単にアクセスできる場所だったので)誰もがこのマネージャークラスに、特にステージ構成に関連する処理ステージを追加することになりました。マネージャークラスには単一の責任はなくなりましたが、代わりにステージを呼び出して構成変更を行う責任がありました。そのため、凝集度が低下していました。

最終的に、マネージャークラスをリファクタリングし、すべてのステージ構成を取り除いてファクトリーに配置する必要がありました。その結果、マネージャーが意図したことを実行することになります。

5
Brady

アプリケーションを壊す最も効果的な方法は、 [〜#〜] god [〜#〜] クラスを作成することです。これらは、多くの情報を追跡し、いくつかの責任を持つクラスです。 1つのコード変更は、クラスの他の部分に影響を与える可能性が高く、そのため、それを使用する他のすべてのクラスに間接的に影響します。新しい機能を追加する以外に変更を敢行する人はいないので、これはさらに大きなメンテナンスの混乱につながります。

次の例は、Personを定義するTypeScriptクラスです。このクラスは、人物の行動とは関係がないため、メール検証を含めないでください。

class Person {
    public name : string;
    public surname : string;
    public email : string;
    constructor(name : string, surname : string, email : string){
        this.surname = surname;
        this.name = name;
        if(this.validateEmail(email)) {
          this.email = email;
        }
        else {
            throw new Error("Invalid email!");
        }
    }
    validateEmail(email : string) {
        var re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
        return re.test(email);
    }
    greet() {
        alert("Hi!");
    }
}

上記のクラスを改善するには、Personクラスから電子メール検証の責任を削除し、その責任を持つ新しいEmailクラスを作成します。

class Email {
    public email : string;
    constructor(email : string){
        if(this.validateEmail(email)) {
          this.email = email;
        }
        else {
            throw new Error("Invalid email!");
        }        
    }
    validateEmail(email : string) {
        var re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
        return re.test(email);
    }
}

class Person {
    public name : string;
    public surname : string;
    public email : Email;
    constructor(name : string, surname : string, email : Email){
        this.email = email;
        this.name = name;
        this.surname = surname;
    }
    greet() {
        alert("Hi!");
    }
}

クラスに単一の責任があることを確認することで、デフォルトでクラスが何を行うか、またどのように拡張/改善できるかを簡単に確認できます。

43
Remo H. Jansen

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

この原則では、クラスを変更する2つの理由がある場合、機能を2つのクラスに分割する必要があると述べています。各クラスは1つの責任のみを処理し、将来1つの変更を行う必要がある場合は、それを処理するクラスでそれを作成します。

変更する2つの異なる理由がある場合、2つの異なる理由で2つの異なるチームが同じコードで作業する可能性があります。それぞれがそのソリューションを展開する必要があります。これは、コンパイルされた言語(C++、C#、Javaなど)の場合、他のチームまたはアプリケーションの他の部分との互換性のないモジュールにつながる可能性があります。

この原理は、結合と凝集の概念に密接に関連しています。結合とは、アプリケーションのさまざまな側面がどのように密接に関連しているかを指し、凝集度とは、特定のクラスまたはパッケージの内容がどの程度密接に関連しているかを指します。クラス自体は[単一ユニット] [1]であり、完全に使用するかまったく使用しないかのいずれかであるため、単一クラスのすべてのコンテンツは密に結合されています。

これに関する私のブログ投稿:

http://javaexplorer03.blogspot.in/2016/12/single-responsibility-principle.html

1
Rajesh Dixit