しかし、私の仕事では、この原則に違反することがよくあります。 この記事では、私が遭遇したSPRを混乱させる最も苦痛な方法を集めました。
最初の方法: シングルトン
シングルトン-基本的な責任に加えて、クラスがインスタンスの数も制御することを意味します。これは単一責任原則に違反します。
シングルトンを作成するのは非常に簡単です。 Wikipediaから数行のコードをお気に入りのIDEにコピーするだけです。 シングルトンはどこにでもあります。オブジェクトを適切な場所に転送する必要はありません。また、メモリを管理する必要もありません。インスタンスは1つだけで、永遠です。 おそらく、この容易さが他の目的にシングルトンを使用する理由です。
シングルトンはコード接続を改善します
シングルトンへの依存は、パブリックインターフェイスには表示されません。 どこにいても、コピーを取得して使用できます。
複雑な依存関係、さらには隠された依存関係(パブリックインターフェイスには表示されないもの)は、アプリケーションの一部に予期しない効果をもたらします。これは、一見コードが変更された部分とは関係ありません。 これにより、予期しないバグが発生します。 さらに、変更によって影響を受ける機能の明白でない領域のために、変更を行った直後にそのようなバグが見つからない場合があります。
シングルトンインスタンスは、タンバリンとダンスせずに置き換えることはできません
シングルトンは自己多型を不可能にします。 したがって、自動テストは不可能です。 実行中にシングルトンの動作を変更することは困難です。 コンポーネントを特別なモードに移行する必要があり、シングルトンの異なる動作が必要になると、痛みと苦痛が生じます。
シングルトンはその状態を保存できます
これにより、クラスメソッド呼び出しの順序を変更するときの動作が変更されます。 シングルトンはどこにでもあるので、呼び出しの順序を制御することはほとんど不可能です。 これにより、さまざまなアーティファクトが発生する可能性があります。 この問題は、コード接続の増加による悪影響を悪化させ、さらに洗練されたバグを生成します。
より安全な生成パターンがあります。
コードの一貫性とそのインスタンスを置き換えることができないことを改善することで、IoCを問題なく解決できます。 たとえば、依存性注入を使用してこの原則を実装すると、クラスのインスタンスの数を制御する責任がなくなり、依存関係がより明確になります。
上記のすべての恐怖にもかかわらず、シングルトンを使用するのが適切な場所があります
シングルトンは、オブジェクトの複数のインスタンスが論理的に存在できない場合に適しています。 たとえば、NSApplication。
既製のライブラリでは、何かをカスタマイズしたり置き換えたりする必要がないか、高価な状況では、シングルトンの使用が正当化されます。
2番目の方法: 建築レイヤーの混合
アーキテクチャーレイヤーを混在させるには多くの方法があります。 それぞれの方法でレーキがレイアウトされます。
モデル内のビジネスロジック。
モデルオブジェクトにビジネスロジックを配置することにより、データストレージ、このデータの処理に関連する追加の責任-主な責任に加えて、それに追加します。 原則として、このアプローチでは、このオブジェクトで実行できる操作のほとんどはモデルオブジェクトに蓄積されます。 SRPの多重違反とは何ですか。
モデルオブジェクトにビジネスロジックが存在すると、ビジネスロジックの一部を別のモデルオブジェクトに再利用できなくなり、モデルの拡張が困難になり、コピーアンドペーストによるポリモーフィズムの実装が促進されます。 同様のオブジェクトを作成する場合、ビジネスロジックを含むコードの一部は、わずかな変更でコピーされます。 このアプローチにより、モデル内のロジックの一部を安全に変更することはほぼ不可能になります。
このような違反の検出は、モデルオブジェクトにメソッドが存在するため、非常に簡単です。
多くの場合、モデルオブジェクトをデバイスメモリに保存するメソッドや、リモートリソースからデータを更新するメソッドがあります。
MVC、MVP、MVVMパターンの誤用
これらのパターンはすべて非常に似ており、略語でも見ることができます。 それぞれにビューとモデルがあります。 これらは、ビューが中間層を介してモデルと対話する方法が異なります。

しかし、これらのパターンにはそれぞれ共通の欠点が1つあります。それは、コントローラー、プレゼンター、またはビューモデルの成長です。 問題の本質は、Viewコンポーネントと、ビジネスロジック(Controller、Presenter、またはView-Model)を格納するコンポーネントの誤解にあります。
ビューには、コントローラーのユーザーインターフェイスを表示するロジックが含まれている必要があり、プレゼンターまたはビューモデルにはビジネスロジックが含まれている必要があります。 MVC iOS SDKに値する個別の単語は、MVCの使用を強制します。 ただし、ほとんどの場合、ユーザーインターフェイスを表示するロジックが含まれているため、UIViewControllerはMVCコントローラーではありません。
この事実により、正しいMVCを実装することはほとんど不可能になります。 最良の場合、UIViewControllerはビューの一部になり、ビジネスロジックは他のレイヤーに移動します。
一方、インターフェイスをController、Presenter、またはView-Modelに表示するために必要なロジックを分離した後は、すべて同じコードが残っている可能性があります。 これは、多くの場合、1つの画面に対してビジネスロジックを含む単一のオブジェクトが作成される一方で、SRPに違反する複数のユーザースクリプトを実装できるためです。
ビジネスロジックを含む各オブジェクトは、複数のユーザーシナリオを実装しないでください。
原則として、多くのユーザースクリプトは、同じ操作、ローカルストレージからのデータの保存と受信、リモートサーバーへのリクエストなどで構成できます。
この場合、ユーザーシナリオに適用されないすべてのロジックをインフラストラクチャレイヤーに取り出す必要があります。
「広大なコントローラ」問題の解決策は、アーキテクチャパターンを適切に使用することです。 コードを記述するときにSRPを順守し、コントローラー、プレゼンター、またはビューモデルから、その主要な責任に関係しないすべてのコードを削除すると、ロジックがより透明になり、ユーザースクリプトがより理解しやすくなり、読みやすくなります。
3番目の方法: NSNotificationCenter
IOS通知は、すべてをすべてのものに接続するための優れた方法です!
NSNotificationCenterはプライベートですが、Singletonを十分に代表しています。 通知はコミュニケーションパターンであり、シングルトンは作成パターンであるという事実にもかかわらず、通知はシングルトンのすべての欠点を保持します。
クラスの主な責任に関係なく、通知の観察を開始すると、SRPに違反します。
通知の使用時に発生する主な問題:
コードの一貫性の改善は、アプリケーションの絶対的にあらゆる部分のあらゆるクラスが通知を送受信できるという事実により達成されます。
通知が送信されると、それを傍受または置換できなくなります。
複数のオブジェクトが1つの通知にサブスクライブしている場合、通知を受信する手順を制御することはできません。
説明されている問題の解決策は、より便利なメカニズムを優先して通知の使用を拒否することです。
例外は、ネットワーク接続の状態の変化や、アプリケーションがバックグラウンドに移動してバックグラウンドを離れるなど、アプリケーションのグローバル状態の変化を通知する通知の使用です。
SRP違反の正式な兆候:
- 最も顕著な兆候の1つは、クラスまたはメソッドのサイズの急増です。
- より多くのプロトコルからのクラスの継承(ISPへの準拠の対象)。
- シングルトンの使用は、SRPの違反を示している場合があります。
- NSNotificationCenterを使用した特定のオブジェクトの状態変化に関する情報の送信(通知によりグローバル状態の変化について通知できます)
- オブジェクト内のユーティリティメソッドの蓄積。
- より多くのパブリッククラスメソッドは、SRP違反を示す場合もあります。
- グループに分割できるプライベートメソッド。 この場合、各グループには独自の責任範囲があります。