免責事項: この一連のブログの参考資料は、Cheng Jie 著の「Dahua Design Pattern」です。
一般に、次の 6 つの原則に従うコードは拡張しやすく再利用可能であると考えられています。 オブジェクト指向言語は、コードを容易に拡張し、高いユーザビリティを実現したい場合は、これに従う必要があります。これら 6 つの原則を満たすように努めてください。必ずしも特定のデザイン パターンに厳密に従う必要はありませんが、コードがこれら 6 つの原則に準拠している場合、そのコードは優れたコードであるとは限りません。 。
1. 単一責任
定義: クラス変更の理由は複数あってはならない。平たく言えば、クラスは 1 つの責任のみを担当します。
シナリオ: クラス T は、責任 P1 と責任 P2 という 2 つの異なる責任を担当します。クラス T を変更するために責任の要求が必要な場合、元の責任 P2 が失敗する可能性があります。関係は次のようになります。
修正: 単一責任の原則に従います。 2 つのクラス T1 と T2 をそれぞれ作成し、T1 が責任 P1 関数を完了し、T2 が責任 P2 関数を完了できるようにします。このように、T1 を変更する場合、責任 P2 のリスクは発生しません。同様に、T2 を変更する場合、責任が P1 のリスクを負うことはありません。構造は次のとおりです。クラスの複雑さを軽減し、クラスは 1 つの責任のみを担当し、ロジックは単純です
2)、クラスの可読性を向上させ、システムの保守性を向上させます
定義: 基本クラスを参照するすべての場所は、そのサブクラスのオブジェクトを透過的に使用できなければなりません。つまり、サブクラスは親クラスの機能を拡張できますが、元のクラスを変更することはできません。関数
シナリオ: クラス A によって完成された関数 P1 があります。ここで関数 P1 を拡張する必要があります。拡張された関数は P です。ここで、P は元の関数 P1 と新しい関数 P2 で構成されます。新しい関数 P は、クラス A のサブクラス B によって完成されます。サブクラス B が新しい関数 P2 を完成すると、以下に示すように、元の関数 P1 が誤動作する可能性があります。
CountPriceByJKL クラスの継承 CountPrice クラスの場合, CountPriceByJKL は Count() メソッドをオーバーライドするため、元の Count メソッドの機能に影響を与える可能性があります。
修正: 継承を使用する場合は、Liskov 置換原則に従います。クラス B がクラス A を継承する場合、新しい関数 P2 を完成させるために新しいメソッドを追加する場合を除き、親クラス A のメソッドをオーバーライドしたり、親クラス A のメソッドをオーバーロードしたりしないようにしてください。
3. 依存性逆転の原則
ここが最も理解しにくいのですが、通常、ビジネス ロジック層はデータ層を呼び出す必要があるため、プロジェクト フレームワークを構築するときに使用されます。スケーラビリティと高い再利用性を実現するには、ビジネス ロジック層がデータ層に依存しないようにする必要があります。データ層でインターフェイスを抽象化し、ビジネス ロジック層をこれに依存させることができます。抽象的なインターフェイス。
シナリオ: クラス A (高レベルモジュール) がクラス B (低レベルモジュール) に直接依存する クラス A をクラス C (低レベルモジュール) に依存するように変更したい場合は、クラスのコードを変更する必要があります。 A.このシナリオでは、通常、クラス A は複雑なビジネス ロジックを担当する高レベル モジュールであり、クラス B と C は基本的なアトミック操作を担当する低レベル モジュールです。クラス A が変更されると、プログラムに不要なリスクが生じます。
AutoSystem クラスが HondaCar または FordCar を制御したい場合、高結合が生成されます。対応するオブジェクトを直接作成する必要があります。
この変更後、ホンダとフォードは、Run、Stop、Turn 関数メソッドを提供する ICar インターフェイスを実装しました。AutoSystem は ICar インターフェイスに依存し、これにより AutoSystem は抽象インターフェイスに依存することになり、AutoSystem クラスがより多くの需要に対応できるようになります。変化します。
1) 低レベルのモジュールには、抽象クラスまたはインターフェイス、あるいはその両方が必要です。
2) 変数の宣言型は、可能な限り抽象クラスまたはインターフェイスにする必要があります。
3) 継承を使用する場合は、リスコフ置換原則に従います。
4. インターフェース分離原則
シナリオ: クラス A はインターフェイス I を通じてクラス B に依存し、クラス C はインターフェイス I を通じてクラス D に依存します。インターフェイス I がクラス A とクラス B の最小インターフェイスでない場合、クラス B とクラス D は実装する必要があります。必要のないメソッドは以下の通りです:
修正: 肥大化したインターフェース I をいくつかの独立したインターフェースに分割し、クラス A とクラス C はそれぞれ必要なインターフェースとの依存関係を確立します。 。つまり、インターフェース分離の原理が採用されています。
注:
1) インターフェースは可能な限り小さくする必要がありますが、制限は必要です。インターフェイスを改良するとプログラミングの柔軟性が向上することは事実ですが、小さすぎるとインターフェイスが多くなり、設計が複雑になります。したがって、それは適度に行う必要があります。
2) インターフェイスに依存するクラスのサービスをカスタマイズし、必要なメソッドのみを呼び出しクラスに公開し、必要のないメソッドを非表示にします。モジュールにカスタマイズされたサービスを提供することに重点を置くことによってのみ、確立される依存関係を最小限に抑えることができます。
3) 結束力を高め、外部との相互作用を減らします。ほとんどのことを達成するためにインターフェイスで使用するメソッドを最小限にします。5. デメテルの法則 (最も知られていない原則)
定義: オブジェクトは他のオブジェクトについての知識を最小限に保持する必要があります。
シナリオ: クラス間の関係が緊密であればあるほど、一方のクラスが変更されると、他方のクラスへの影響が大きくなります。
単純に理解すると、クラスのメソッドと属性をプライベートにできる場合は、できるだけプライベートにするようにしてください。
1) 直接の友人とのみ通信し、見知らぬ人には話さないでください。
2) この原則を過度に使用すると、システムの複雑さが増加します。したがって、ディミットの法則を使用する場合は、明確な構造と高い凝集性と低い結合性の両方を達成するために、トレードオフを繰り返し検討する必要があります。
6. オープンクローズ原則
定義: クラス、モジュール、関数などのソフトウェア エンティティは、拡張に対してオープンであり、変更に対してクローズである必要があります。
シナリオ: ソフトウェアのライフサイクル中に、変更、アップグレード、メンテナンスなどによりソフトウェアの元のコードを修正する必要がある場合、古いコードにエラーが導入されたり、コードを再構築しなければならない場合があります。関数全体をテストする必要があるため、元のコードを再テストする必要があります。
推奨事項: ソフトウェア要件が変更された場合は、既存のコードを変更するのではなく、ソフトウェア エンティティの動作を拡張することによって変更を実現するようにしてください。