私たちは日々の開発において、いくつかの原則やパターンに従わなければならないことがよくありますが、これらは実際に開発の先人たちがまとめたものであり、私たちがどのようなソフトウェア開発を行うとしても、それは私たちにとって有益であり、無害です。この記事はこれらの原則を要約し、その説明の意味を説明するものであり、この記事がすべての人にインスピレーションを与え、Java の知識をより良く学ぶのに役立つことを願っています。 apache php mysql
始めましょう!
オブジェクト指向の基本原則(固体)は5つですが、よく言われるこの5つ以外にも、デメテルの法則や合成と再利用の原則などもあります。 , したがって、一般的な記事では、書くための 6 つまたは 7 つの原則があります。さらに、他の関連書籍やインターネットに掲載されているいくつかの原則も示します。原則、クラスでは、1 つのことだけを実行し、1 つのことだけでそれを変化させるのが最善です。単一責任の原則は、結合性が低く、凝集性が高いというオブジェクト指向の原則の拡張として、責任は凝集性を高め、変化の原因を減らすための変化の原因として定義されます。
原理分析
クラス (またはモジュールほど大きいかメソッドほど小さい) が負う責任が大きいほど、再利用される可能性は低くなり、クラスが負う責任が多すぎる場合、それは同等になります。これらの責任は結合されており、いずれかの責任が変更されると、他の責任の運用に影響を与える可能性があります。
クラスの責任には、主にデータ責任と動作責任の 2 つの側面が含まれます。データ責任はその属性を通じて反映され、行動責任はそのメソッドを通じて反映されます。
単一責任の原則は、多くのコード リファクタリング手法に見られる、さまざまなクラスの責任と分離を発見する必要がある原則です。 、クラスの複数の責任を発見するには、設計者に強力な分析能力と設計能力、および関連するリファクタリングの経験が必要です。
利点
クラスの複雑さが軽減され、クラスの責任が明確になります。たとえば、データに対する責任と行動に対する責任は明確です。
クラスの可読性と保守性を向上させます。
変更によって引き起こされるリスクを軽減します。変更は不可欠です。インターフェースの単一の責任が適切に行われている場合、インターフェースの変更は対応するクラスにのみ影響します。他のインターフェイスへの影響を軽減し、システムの拡張性と保守性に非常に役立ちます。
例
Open - ClosedPrinciple、OCP、拡張のためにオープン、変更のためにクローズ(デザインパターンの核となる原則)OOpen and Closed Principle OCP
原理分析
ニーズに応じてソフトウェア エンティティが変更される場合、既存のコードを変更するのではなく、ソフトウェアの新しいニーズを満たす新しい動作を提供するように既存のソフトウェア エンティティを拡張するようにしてください。適応性と柔軟性の程度。既存のソフトウェア モジュール、特に最も重要な抽象化レイヤー モジュールは変更できないため、変化するソフトウェア システムにある程度の安定性と継続性が与えられます。
オープン-クローズド原則を実現するための鍵は抽象化です。「オープン-クローズド」原則では、抽象クラスまたはインターフェイスの変更は許可されず、具体的な実装クラスおよび抽象インターフェイスの拡張は許可されます。 「オープン-クローズド」の原則では、「-」は「クロージャ」の原則において非常に重要な役割を果たします。つまり、変化する可能性のある要件を予測し、すべての可能な既知の拡張を予測します。したがって、ここでは「抽象化」が鍵となります。
変動性の閉鎖原則: システムの変動要因を見つけてカプセル化する。これは、変動要因を複数のクラスに配置したり、隅々に分散させたりしないでください。プログラムの変数要素をカプセル化する必要があります。また、一緒に使用する変数要素をブロックで囲わないように注意してください。サイズが大きすぎるクラスの出現を避ける必要があります。プログラムに芸術的な風味を加えて、プログラムを芸術的にすることが私たちの目標です
例
デザイン モードでは、テンプレート メソッド モードとオブザーバー モードの両方が有効になります。閉鎖の原則。ここをクリックすると、高可用性アーキテクチャ設計のための 9 つのソリューションの詳細な説明が表示されます。
リスコフ置換原理、LSP: 基本クラスが出現できる場所であればどこでも、サブクラスも出現でき、この概念は継承メカニズムの制約仕様として表現され、サブクラスのみが置き換えられます。基本クラスが使用されている場合にのみ、システムは実行時にサブクラスを識別できます。これが継承を確実に再利用するための基礎となります。
定義
最初の定義方法は比較的厳密です。型 S のすべてのオブジェクト o1 に対して、型 T のオブジェクト o2 が存在する場合、T で定義されたすべてのプログラム P がすべてのオブジェクト o1 に置き換えられます。 o2 の場合、プログラム P の動作は変わりません。その場合、型 S は型 T のサブタイプになります。
2 番目のわかりやすい定義: 基本クラス (親クラス) を参照するすべての場所は、そのサブクラスのオブジェクトを透過的に使用できなければなりません。つまり、サブクラスは、それが出現する場所の基本クラスを置き換えることができなければなりません。サブクラスは、基本クラスに基づいて新しい動作を追加することもできます。
(リスコフ置換原理は、2008 年チューリング賞受賞者、米国初のコンピューター サイエンスの女性医師、MIT 教授、およびカーネギー メロン大学のジャネット ウィング教授であるバーバラ リスコフによって 1994 年に提案されました。原文は次のとおりです。以下のように:q(x) を T 型のオブジェクト x について証明可能なプロパティとします。すると、q(y) は S 型のオブジェクト y に対して真になります。ここで、S は T のサブタイプです。)
原理分析
が話しています。基本について クラスとサブクラスの関係 この関係が存在する場合にのみ、リスコフ置換原理が存在します。正方形は長方形であるということは、リスコフ置換原理を理解する典型的な例です。
リスコフ置換原則は、一般的な方法で表現できます。ソフトウェアで基本クラス オブジェクトを使用できる場合は、そのサブクラス オブジェクトも使用できる必要があります。基本クラスがそのサブクラスで置き換えられた場合、プログラムはエラーや例外を生成しません。逆に、ソフトウェア エンティティがサブクラスを使用する場合は、基本クラスを使用できない可能性があります。
リスコフ置換原則は、開始および終了原則を実装するための重要な方法の 1 つです。サブクラス オブジェクトは、基本クラス オブジェクトが使用される場所であればどこでも使用できるため、プログラム内でオブジェクトを定義するために基本クラスの型を使用するようにしてください。実行時にそのサブクラスの型を変更し、親クラスのオブジェクトをサブクラスのオブジェクトに置き換えます。
(インターフェース分離原則、ISL): クライアントは、必要のないインターフェースに依存すべきではありません。 (この法則はデメテルの法則と一致します)
定義
クライアントは、必要のないインターフェースに依存すべきではありません。
別の定義方法: インターフェイスが大きすぎる場合、このインターフェイスを使用するクライアントは、それに関連するメソッドを知るだけで済みます。
この定義のインターフェイスは、定義されたメソッドを参照していることに注意してください。たとえば、クラスのパブリック メソッドを外部から呼び出すなどです。このメソッドは外部世界へのインターフェースです。
原理分析
1) インターフェース分離の原理は、単一の全体的なインターフェースを使用するのではなく、複数の特殊なインターフェースを使用することを指します。各インターフェースは比較的独立した役割を担うべきであり、それ以上でも以下でもありません。実行すべきでないことは実行すべきではありませんが、実行すべきことはすべて実行する必要があります。
インターフェースは 1 つの役割のみを表し、各役割は独自の特定のインターフェースを持ちます。この原則は「役割分離原則」と呼ぶことができます。
インターフェイスは、クライアントが必要とする動作のみを提供します。つまり、クライアントが必要としない動作は、クライアントに大きなインターフェイスではなく、できるだけ小さい別のインターフェイスを提供する必要があります。総合的なインターフェース。
2) インターフェース分離原則を使用してインターフェースを分割する場合、まず単一責任原則を満たし、インターフェース内で関連する操作のセットを定義する必要があります。また、高い凝集性を満たすことを前提として、インターフェース内のメソッドの数は少なくなります。インターフェイスは良いほど良いです。
3) システムの設計時にカスタマイズされたサービスを使用できます。つまり、さまざまなクライアントに異なる幅のインターフェイスを提供し、ユーザーが必要とする動作のみを提供し、ユーザーが必要としない動作を非表示にすることができます。
依存性反転原則は、特定の実装ではなく抽象化に依存します。具体的には、高レベルのモジュールは低レベルのモジュールに依存しません。抽象は具体に依存せず、具体は抽象に依存します。
定義
高レベルのモジュールは低レベルのモジュールに依存すべきではなく、すべて抽象化に依存する必要があります。抽象化は詳細に依存すべきではなく、詳細は抽象化に依存する必要があります。簡単に言うと、依存関係逆転の原則により、クライアントは抽象結合に依存する必要があります。原理式:
1) 抽象化は詳細に依存すべきではありません。詳細は抽象化に依存する必要があります。
2) プログラミングは実装のためではなくインターフェースのためにあるべきです。
原理分析
1) 開閉原理がオブジェクト指向設計の目標である場合、依存関係反転原理はオブジェクト指向設計の「開閉」原理を達成する手段です。最適な「開始と終了」の原則を達成したい場合は、依存関係の逆転の原則に可能な限り従う必要があります。依存関係逆転原理は「抽象化」に最適な仕様と言えます!私個人としては、依存関係逆転原理はリヒター置換原理を補完するものでもあると感じています。リスコフ置換原理を理解すれば、依存関係逆転原理も簡単に理解できるはずです。
2) 依存関係逆転の原則を実装する一般的な方法の 1 つは、コードで抽象クラスを使用し、構成ファイルに具象クラスを置くことです。
3) クラス間の結合: ゼロ結合関係、具体的結合関係、抽象的結合関係。依存関係反転原則では、クライアントは抽象結合に依存する必要があります。抽象的な結合が依存関係反転原則の鍵です。
例
この依存関係の逆転を理解するには、まずオブジェクト指向設計における依存関係の概念を理解する必要があります:
Dependency (依存関係): 特定のものへの変更は、それを使用する他のものに影響を与える可能性がある使用関係です。もの、依存関係は、あるものが別のものを使用していることを示す必要がある場合に使用されます。 (クラス A の変更がクラス B の変更を引き起こすと仮定すると、クラス B はクラス A に依存していると言われます。) ほとんどの場合、依存関係は、別のクラスのオブジェクトをパラメータとして使用して、あるクラスのメソッドに反映されます。 。 UML では、依存関係は、依存関係者から依存関係者を指す矢印付きの破線で表されます。
例: 特定のシステムは、さまざまなデータ ソースからのデータを、データベース (DatabaseSource) のデータやテキスト ファイル (TextSource) のデータなど、複数の形式に変換できるデータ変換モジュールを提供します。最終形式は XML です。ファイル (XMLTransformer)、XLS ファイル (XLSTransformer) など。
要件の変更により、新しいタイプのデータ ソースまたは新しいファイル形式が追加されるたびに、システムはクライアント クラス MainClass のソース コードを追加する必要がある場合があります。新しいクラスを使用するには、 を変更する必要がありますが、開始と終了の原則に違反します。現在、依存関係逆転の原則を使用してリファクタリングされています。ここをクリックすると、高可用性アーキテクチャ設計のための 9 つのソリューションの詳細な説明が表示されます。
もちろん、特定の状況に応じて、AbstractSource を AbstractStransformer に注入することもできます。依存関係の注入には、次の 3 つの方法があります。
それは、新しいオブジェクトの一部の既存のオブジェクトを使用して、それらを新しいオブジェクトの一部にすることです。新しいオブジェクトは、これらのオブジェクトに委任することで、既存の機能を再利用するという目的を達成します。つまり、合成/集約を使用し、継承は使用しないようにしてください。 原理分析
1) オブジェクト指向設計では、既存の設計と実装は、2 つの基本的な方法、つまり合成/集約関係または継承を通じて、異なる環境で再利用できます。
継承と再利用: 実装が簡単で、拡張も簡単です。システムのカプセル化を破棄します。基本クラスから継承された実装は静的であり、実行時に変更できず、限られた環境でしか使用できません。 (「ホワイト ボックス」の再利用)
構成/集約の再利用: 結合度は比較的低く、メンバー オブジェクトの操作は選択的に呼び出され、実行時に動的に実行できます。 (「ブラック ボックス」の再利用)
2) 結合/集約によりシステムの柔軟性が高まり、クラス間の結合が減少し、1 つのクラスでの変更が他のクラスに与える影響が比較的少ないため、一般的には結合/集約が推奨されます。再利用を実現するには、次に継承を考慮します。継承を使用する場合は、リスコフ置換原則に厳密に従う必要があります。継承を効果的に使用すると、問題が理解され、複雑さが軽減されます。一方、継承を乱用すると、システムの構築とメンテナンスが困難になります。システムは複雑なので、継承の再利用を慎重に使用する必要があります。
3) この原則とリスコフ置換原則は、どちらも「オープン-クローズ」原則を具体的に実現するための仕様です。この原則に違反すると、「オープン-クローズ」原則を実現できません。まず、合成と集約の概念を理解する必要があります:
注: 集約と結合の違いは何ですか?合成(組み合わせ):全体と部分の関係を示し、全体に基づいて存在する関係を指します(全体と部分は分離できません)。たとえば、頭の場合、目と口は組み合わせの関係です。 . 頭がなければ目と口は存在せず、それらは切り離せないものです。 UML では、構成関係は黒菱形の直線で表されます。
集約: 集約は合成関係よりも強い依存関係であり、ネジと車のおもちゃ、ネジの関係など、全体と部分の関係も表します。他のデバイスの上でネジを分離した後も、おもちゃに使用できます。 UML では、集計関係は中空のひし形の直線で表されます。
デメテルの法則
(デメテルの法則、LoD: システム内のクラスは、クラス間の結合を減らすために他のクラスと対話しないように努めるべきです
定義
最小知識の原則とも呼ばれます(最低限の知識の原則、または LKP と略されます) いくつかの定義形式:
見知らぬ人とのみ通信する
直属の友達とのみ通信する
ソフトウェア ユニットは他のユニットについての知識を最小限に抑え、それ自体のユニットと密接に関連するソフトウェア ユニットに限定されます。つまり、オブジェクトは他のオブジェクト A クラスについても最小限の知識しか持たない必要があります。結合する必要があるクラスや呼び出す必要があるクラスについては最低限知っておく必要があります。私には、(結合されたクラスまたは呼び出されたクラス)の内部がどれほど複雑であるかは関係ありません。私はあなたが提供するパブリックメソッドだけを知っています。
デメテルの法則では、オブジェクトのフレンドには次のカテゴリが含まれます: (1) 現在のオブジェクト自体(this); (2) パラメータの形式で現在のオブジェクトのメソッドに渡されるオブジェクト (4) 現在のオブジェクトがセットの場合、セット内の要素もフレンドです。 (5) 現在のオブジェクトによって作成されたオブジェクト
狭義のディミットの法則: クラス間の結合を減らすことができますが、多数の小さなメソッドを追加するとシステムに問題が発生します。システムの隅々に散在すると、各部分が遠く離れたオブジェクトに直接関係しないため、システムのローカル設計が簡素化されますが、システムの異なるモジュール間で競合が発生し、システム間の通信効率が低下します。システムの異なるモジュール間の調整が困難になるため、高可用性アーキテクチャ設計のための 9 つのソリューションの詳細な説明を参照するには、ここをクリックしてください。
一般化されたデメテルの法則: オブジェクト間の情報の流れ、および情報の制御を指します。影響は主に情報隠蔽の制御にあり、情報隠蔽により各サブシステムが分離され、それらを独立して開発、最適化、使用、変更できるようになり、同時に他のモジュールに依存するソフトウェアの再利用が促進されます。システムの規模が大きくなればなるほど、情報を隠蔽することの重要性はより顕著になります。
ディミットの法則の主な目的は、情報の過負荷を制御することです。
他のクラスへの参照に関して、あるオブジェクトから他のオブジェクトへの参照は最小限に抑える必要があります。
システム内のクラスは、クラス間の結合を減らすために他のクラスと対話しないようにする必要があります。システムでは、拡張するときにこれらのクラスを変更する必要がある場合があり、クラス間の関係によって変更の複雑さが決まります。相互作用が多ければ多いほど、修正は難しくなります。逆に、相互作用が小さければ、修正は難しくなりません。たとえば、クラス A はクラス B に依存し、クラス B はクラス C に依存します。クラス A を変更するときは、クラス B が影響を受けるかどうか、およびクラス B の影響がクラス C に影響するかどうかを考慮する必要があります。 この時点でクラス C がクラス D に依存するのであれば、笑、そのような修正は耐えられると思います。
オブジェクト指向設計のその他の原則
変更のカプセル化
継承を減らし、合成をより多く使用する
実装プログラミングではなくインターフェースのプログラミング
相互作用するオブジェクト間の疎結合設計に努める
クラスは拡張機能の開発と変更に対してクローズされるべきです (オープン-クローズド OCP 原則)
抽象化に依存し、具象クラスに依存しないでください (依存関係逆転 DIP 原則)
親しい友人の原則: 友達とのみ話します (最小の原則)知識、デメテルの法則)
注: オブジェクトは他のオブジェクトについてはできる限り知識を持たず、メソッド呼び出しを範囲内に保ち、次のスコープに属するメソッドのみを呼び出す必要があります: オブジェクト自体 (ローカル メソッド) オブジェクトのコンポーネントメソッドのパラメータとして渡されます オブジェクト このメソッドによって作成またはインスタンス化された任意のオブジェクト
私のところに来ないでください (電話してください) 私はあなたのところに行きます (電話してください) (ハリウッド原則)
クラスの理由は 1 つだけです変更 (単一責任 SRP 原則)
リスコフ置換原則を説明できますか?
厳密な定義: 型 S のオブジェクト o1 ごとに、型 T のオブジェクト o2 が存在し、すべてのプログラム P が T で定義される場合すべてのオブジェクトで使用されます。o1 が o2 を置き換えても、プログラム P の動作は変わりません。その場合、型 S は型 T のサブタイプになります。
よく使われる表現: 基本クラス (親クラス) を参照するすべての場所は、そのサブクラスのオブジェクトを透過的に使用できなければなりません。つまり、サブクラスは親クラスの機能を拡張できますが、親クラスの元の機能を変更することはできません。これには次の 4 つのレベルの意味が含まれます:
サブクラスは親クラスの抽象メソッドを実装できますが、親クラスの非抽象メソッドをオーバーライドすることはできません。
独自の一意のメソッドをサブクラスに追加できます。
サブクラスのメソッドが親クラスのメソッドをオーバーライドする場合、メソッドの前提条件 (つまり、メソッドの仮パラメータ) は、親クラスのメソッドの入力パラメータよりも緩くなります。
サブクラスのメソッドが親クラスの抽象メソッドを実装する場合、メソッドの事後条件 (メソッドの戻り値) は親クラスの事後条件よりも厳しくなります。
どのような状況でディミットの法則に違反しますか?なぜこれが問題になるのでしょうか?
デメテルの法則は、クラス間の結合を減らすために「見知らぬ人とではなく、友達とのみ話す」ことを推奨しています。
オープンクローズ原則に準拠したデザインパターンの例を教えてください。
オープンクローズの原則では、コードが拡張に対してオープンであり、変更に対してクローズであることが必要です。これは、新しい機能を追加する場合、すでにテストされたコードを変更せずに、新しいコードを簡単に追加できることを意味します。新しい戦略が必要な場合は、コア ロジックを変更せずに、インターフェイスを実装して構成を追加するだけで済みます。実際の例は Collections.sort() メソッドです。これは戦略パターンに基づいており、新しいオブジェクトに対して sort() メソッドを変更する必要はありません。独自のコンパレータインターフェイス。
フライウェイトモード(フライウェイトモード)はいつ使用するのですか?
Flyweight パターンは、オブジェクトを共有することで、過剰なオブジェクトの作成を回避します。フライウェイト パターンを使用するには、オブジェクトを安全に共有できるようにオブジェクトが不変であることを確認する必要があります。 JDK の String プール、Integer プール、Long プールはすべて、Flyweight パターンを使用する良い例です。
end:
質問があれば、質問して一緒にコミュニケーションしましょう。
関連記事:
関連動画:
以上がすべての Java アーキテクトはこれら 6 つの設計原則を知っていますか?マスターしなければなりませんの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。