カップリング。ベストプラクティス


11

このスレッドに続いて、私は始めました

シングルトンパターン

クラスがどのように結合されているか、そして疎結合を達成するための最良の方法について考えさせられました。私は新しいプログラマー(最初の仕事を始めて4か月)であり、これが実際に私がこれに与えた最初の考慮事項であり、コンセプトを理解することに非常に熱心であることに留意してください。

では、疎結合と重結合を正確に構成するものは何ですか?私の現在の(そして最初のプロジェクト)では、ac#winformsプロジェクトに取り組んでいます.GUIセクションはオブジェクトとイベントへのサブクリブを作成します標準のdatagridviewをラップして追加の機能を追加する)を作成し、それをGUIにアタッチしています。

私は本当に悪い習慣に陥り、コーディングが不十分になりたくないので、あなたの反応に感謝します。

回答:


11

ここでコードを疎結合するには、覚えておくべきいくつかの簡単なことがあります。

パート1:

技術的には「懸念の分離」として知られています。各クラスには特定の役割があり、ビジネスロジックまたはアプリケーションロジックを処理する必要があります。両方の責任を兼ね備えたクラスを避けてください。つまり、データを管理する(広義の)クラスはアプリケーションロジックであり、データを使用するクラスはビジネスロジックです。

個人的に私はこれを(自分の小さな世界では)と呼んでいcreate it or use itます。クラスはオブジェクトを作成するか、両方を実行しないオブジェクトを使用する必要があります。

パート2:

関心の分離を実装する方法。
出発点として、2つの簡単な手法があります。

注:設計パターンは絶対的なものではありません。
それらは状況に合わせてカスタマイズされることになっていますが、すべてのアプリケーションに似た基礎となるテーマを持っています。ですから、以下の例を見て、厳密にこれに従う必要があると言ってはいけません。これらは単なる例です(そして、少し工夫されています)。

依存性注入

これは、クラスが使用するオブジェクトを渡す場所です。インターフェースに基づいて渡す​​オブジェクト。これにより、クラスはそれをどう処理するかを認識しますが、実際の実装を知る必要はありません。

class Tokenizer
{
    public:
        Tokenizer(std::istream& s)
            : stream(s)
        {}
        std::string nextToken() { std::string token; stream >> token;return token;}
    private:
        std::istream& stream;
};

ここで、ストリームをTokenizerに注入します。トークナイザーは、std :: istreamのインターフェースを実装している限り、ストリームのタイプを認識しません。

サービスロケーターパターン

サービスロケーターパターンは、依存性注入のわずかなバリエーションです。使用できるオブジェクトを与えるのではなく、使用したいオブジェクトを見つける(作成する)方法を知っているオブジェクトを渡します。

class Application
{
     public:
         Application(Persister& p)
             : persistor(p)
         {}

         void save()
         {
             std::auto_ptr<SaveDialog> saveDialog = persistor.getSaveDialog();
             saveDialog.DoSaveAction();
         }

         void load()
         {
             std::auto_ptr<LoadDialog> loadDialog = persistor.getLoadDialog();
             loadDialog.DoLoadAction();
         }
    private:
        Persister& persistor;
};

ここでは、アプリケーションオブジェクトに永続オブジェクトを渡します。保存/読み込みアクションを実行すると、永続化機能を使用して、アクションの実行方法を実際に知っているオブジェクトが作成されます。注:再び永続化はインターフェースであり、状況に応じて異なる実装を提供できます。

これはpotentially、アクションをインスタンス化するたびに一意のオブジェクトが必要な場合に便利です。

個人的には、これは単体テストを書くのに特に役立つと思います。

パターンの注意:

デザインパターンは、それ自体が大きなテーマです。これは、疎結合を支援するために使用できるパターンの排他的なリストではありません。これは一般的な出発点です。

経験を積むと、正式な名前を使用しなかったというだけで、これらのパターンを既に使用していることに気付くでしょう。彼らの名前を標準化することで(そして誰もがそれらを学べるようにすることで)、アイデアを伝えることは簡単で迅速であることがわかります。


3
@ダレン・ヤング:受け入れてくれてありがとう。しかし、あなたの質問はわずか3時間です。私は1日かそこらで戻ってきて、他の人がより良い答えを提供していないことを確認します。
マーティンヨーク

素晴らしい反応をありがとう。懸念の分離について....使用するためにいくつかのデータを必要とするクラスがあり、そのデータで何かをします。これは、過去にクラスを設計した方法です。したがって、データを取得し、それを正しいフォームに適合させ、次にデータを実際に使用する別のクラスに適合させるクラスを作成する方が良いでしょうか?
ダレンヤング

@Darren Young:すべてのプログラミングと同様、線は灰色でぼやけており、明確に定義されていません。コードを読み取らずに正確な応答を返すのは困難です。しかし、私が話すときmanaging the data、変数を参照しています(実際のデータではありません)。したがって、ポインターのようなものは、リークしないように管理する必要があります。ただし、データを注入したり、データの取得方法を抽象化したりすることができます(クラスをさまざまなデータ取得方法で再利用できます)。申し訳ありませんが、これ以上正確にすることはできません。
マーティンヨーク

1
@Darren Young:@StuperUserの回答で述べたとおり。船外に出ないでください(別名minutae of loose coupling(その言葉はミヌタエが大好きです))。プログラミングの秘密は、いつテクニックを使用するかを学ぶことです。使いすぎると、コードが混乱する可能性があります。
マーティンヨーク

@Martin-アドバイスをありがとう。私はそれが現在苦労しているところだと思います...私は常にコードのアーキテクチャを心配し、またC#を使用している特定の言語を学ぼうとしています。経験と、このようなことを学びたいという私の願望が来ると思います。あなたのコメントに感謝します。
ダレンヤング

6

私はASP.NET開発者なので、WinFormsカップリングについてはあまり知りませんが、UI、ドメイン、データアクセスレイヤー(DAL)の3層アプリケーションアーキテクチャを想定して、N-Tier Webアプリについては少し知っています。

疎結合は抽象化に関するものです。

@MKOは、アセンブリを別のアセンブリ(たとえば、ドメインプロジェクトを使用する新しいUIプロジェクト、データベースではなくスプレッドシートに保存する新しいDAL)に置き換えることができるかどうかを示すため、疎結合があります。ドメインとDALがチェーンのさらに下のプロジェクトに依存している場合は、結合が緩くなる可能性があります。

疎結合されているものの1つの側面は、オブジェクトを同じインターフェースを実装する別のものと置き換えることができるかどうかです。それは実際のオブジェクトに依存するのではなく、それが何をするか(そのインターフェース)の抽象的な説明に依存します。
疎結合、インターフェース、依存性インジェクター(DI)および制御の反転(IoC)は、テスト容易性を設計するための分離の側面に役立ちます。

たとえば、UIプロジェクトのオブジェクトは、ドメインプロジェクトのリポジトリオブジェクトを呼び出します。
あなたは、作成することができます偽の実装、テスト用の用途の下でコード、テストのために特別な行動を記述(そのリポジトリと同じインターフェイスというオブジェクトをスタブ /削除を節約し、生産コードを防止するためには、/呼び出されますをし、モックスタブとして作用することキープトラックテスト目的での偽オブジェクトの状態)。
つまり、呼び出される本番コードはUIオブジェクトのみになり、テストはそのメソッドに対してのみ行われ、テストの失敗はそのメソッドの欠陥を切り分けます。

また、VSの[分析]メニュー(使用しているバージョンによって異なります)には、プロジェクトのコードメトリックを計算するツールがあり、その1つはクラスカップリングです。これについては、MSDNのドキュメントを参照してください。

取得しないでくださいTOOが NOのチャンスは、物事が(複数のUIを持つ例えば、Aドメインプロジェクト)再利用を取得しており、製品の寿命が小さいことがあるかどう、けれども疎結合のminutaeで泥沼、そして疎結合が少なくなります優先順位は変わりません(引き続き考慮されます)が、コードをレビューするアーキテクト/技術リーダーの責任です。


3

カップリングとは、あるクラスが別のクラスについて持っている直接的な知識の度合いを指します。これは、カプセル化と非カプセル化として解釈されることを意図していません。これは、あるクラスの別のクラスの属性または実装に関する知識への参照ではなく、その別のクラス自体の知識への参照です。強い結合は、依存クラスに、必要な動作を提供する具体的なクラスへのポインタが直接含まれている場合に発生します。依存クラスを変更することなく、依存関係を置換したり、その「署名」を変更したりすることはできません。疎結合は、依存クラスにインターフェイスへのポインタのみが含まれる場合に発生し、1つまたは複数の具象クラスによって実装できます。依存クラスの依存関係は、インターフェイスで指定された「契約」に対するものです。クラスの実装が提供しなければならない定義済みのメソッドやプロパティのリスト。したがって、インターフェイスを実装するクラスは、クラスを変更することなく、依存クラスの依存関係を満たすことができます。これにより、ソフトウェア設計の拡張性が可能になります。インターフェイスを実装する新しいクラスを記述して、一部またはすべての状況で現在の依存関係を置き換えることができます。依存クラスを変更する必要はありません。新しいクラスと古いクラスは自由に交換できます。強結合ではこれができません。 参照リンク。


3

5つの堅実な原則をご覧ください。SRPに準拠すると、ISPとDIPはカップリングを大幅に低下させ、DIPは圧倒的に最も強力なカップリングになります。これは、すでに説明したDIの下にある基本原則です。

また、GRASPは一見の価値があります。それは抽象的な概念(最初は実装するのが難しいでしょう)と具体的なパターン(実際には助けになるかもしれません)の奇妙な組み合わせですが、おそらく今は美しさが一番心配ではありません。

そして最後に、IoCに関するこのセクションは、一般的な手法への入り口として非常に役立つことがあります。

実際、私はstackoverflowに関する質問を見つけました。具体的な問題に対するSOLIDの適用例を示しています。興味深い読み物になるかもしれません。


1

ウィキペディアによると:

コンピューティングおよびシステム設計において、疎結合システムとは、各コンポーネントが他の個別のコンポーネントの定義に関する知識をほとんどまたはまったく使用しないシステムです。

密結合の問題により、変更が困難になります。(多くの作家は、これが主にメンテナンス中に問題を引き起こすことを示唆しているようですが、私の経験では、初期開発にも関連しています。)結合されているモジュール内。多くの場合、これには他のモジュールの変更などが必要です。

対照的に、疎結合システムでは、変更は比較的孤立しています。したがって、それらは低コストであり、より高い信頼性で作成できます。

あなたの特定の例では、イベント処理のものは、GUIと基礎となるデータの間の分離を提供します。ただし、他に分離可能な領域があるように聞こえます。特定の状況の詳細がなければ、特定するのは困難です。ただし、次のような3層のアーキテクチャから始めることもできます。

  • データの保存と取得のロジック
  • ビジネスの論理
  • UIの実行に必要なロジック

考慮すべき点は、開発者が1人の小規模な1回限りのアプリケーションの場合、すべてのレベルで疎結合を実施するメリットは努力に値しない場合があることです。一方、複数の開発者がいる大規模で複雑なアプリケーションは必須です。最初は、抽象化を導入し、そのアーキテクチャに関するコードに不慣れな開発者を教育するのにコストがかかります。ただし、長期的には、疎結合は、コストをはるかに上回る利点を提供します。

疎結合システムの設計を真剣に考えている場合は、SOLIDの原則と設計パターンを読んでください。

しかし、実現する重要なことは、これらのパターンと原則がまさにそれであるということです-パターンと原則。それらはルールではありません。これは、実用的かつインテリジェントに適用する必要があることを意味します

パターンに関しては、どのパターンも「正しい」実装は1つもないことを理解することが重要です。また、独自の実装を設計するためのcookie-cutterテンプレートもありません。それらは、優れたソリューションがどのような形をとるかを示し、設計決定を他の開発者と通信するための共通言語を提供します。

ではごきげんよう。


1

依存性注入、戦略パターン、およびイベントを使用します。一般に、設計パターンを読んで、それらはすべて疎結合と依存関係の削減に関するものです。依存関係の注入と戦略パターンにはいくつかのインターフェースが必要ですが、イベントはあなたが得るほど疎結合だと思います。

良いトリックは、異なるライブラリ/アセンブリにクラスを配置し、それらができるだけ少ない他のライブラリに依存するようにすることです。


4
コンドームは抽象的なIT用語ですか、それとも単純にしゃれていませんか?
ダレンヤング

3
依存性注入コンテナの別名です。
MCHL

2
また、ウイルスの拡散を防ぐ素晴らしい方法です。同じことを話しているのでしょうか?
ソバ

1
ヘビーカップリングは、多くの場合、バックエンドで行われます
Homde

1
見出しの設定はフォーマットを乱用することはほとんどありません
-Homde

0

別のビューを提供します。各クラスが優れたAPIであるという観点でこれを考えています。メソッドが呼び出される順序は明らかです。彼らがすることは明らかです。メソッドの数を必要最小限に減らしました。たとえば、

init、open、close

setTheFoo、setBar、initX、getConnection、close

1つ目は明らかで、素晴らしいAPIのように見えます。2番目の呼び出しは、間違った順序で呼び出されるとエラーを引き起こす可能性があります。

呼び出し元を変更して再コンパイルする必要について心配する必要はありません。いくつかの新しいコードと15年前のコードを大量に管理しています。通常、変更を加えるときにコンパイラエラーが発生します。そのために、意図的にAPIを壊すことがあります。これにより、各呼び出し元の影響を考慮する機会が与えられます。ブラックボックスを使用せずにコードを視覚的にトレースできるようにしたいので、依存関係注入の大ファンではありません。また、コンパイラにできるだけ多くのエラーをキャッチしてもらいたいです。

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