[解決済み】Dependency Inject (DI)の "フレンドリー "なライブラリ
質問
C#のライブラリの設計について考えているのですが、そのライブラリにはいくつかの異なるハイレベルな関数があります。もちろん、これらの高レベルの関数は、C#のライブラリで実装されます。 ソリッド というクラス設計の原則があります。そのため、おそらく消費者が定期的に直接使用することを目的としたクラスや、より一般的な「エンドユーザー」クラスの依存関係にある「サポート」クラスが存在することでしょう。
問題は、そうなるようにライブラリを設計する最善の方法は何かということです。
- DIアグノスティック - 一般的なDIライブラリ(StructureMap、Ninjectなど)の1つか2つに基本的なサポート"を追加することは合理的だと思いますが、コンシューマはどのDIフレームワークでもライブラリを使用できるようにしたいのです。
- DIを使用しない場合 - ライブラリの消費者がDIを使用しない場合でも、ライブラリはできるだけ使いやすく、ユーザーが使用したい本当のクラスに到達するために必要な、重要でない依存関係をすべて作成しなければならない作業量を減らす必要があります。
現在考えているのは、一般的なDIライブラリ(StructureMapレジストリやNinjectモジュールなど)用のいくつかのquot;DI登録モジュールと、非DIでこれらのいくつかのファクトリへのカップリングを含む一連のファクトリクラスを提供することです。
いかがでしょうか?
解決方法は?
これは、DIが以下のようなものであることを理解すれば、実は簡単なことなのです。 パターンと原則 技術ではありません。
DI Containerに依存しない方法でAPIを設計するには、以下の一般原則に従います。
実装ではなく、インターフェイスにプログラムする
この原則は、実は、(記憶ではあるが)以下の引用である。 デザインパターン しかし、それは常にあなたの 真の目標 . DIはその目的を達成するための手段に過ぎない .
ハリウッドの原則を適用する
ハリウッドプリンシプルをDIで言うと DIコンテナを呼ぶな。 .
コード内からコンテナを呼び出して、依存関係を直接要求してはいけません。暗黙的に依存関係を求めるには コンストラクタ・インジェクション .
コンストラクタ・インジェクションの使用
依存関係が必要なとき、それを求める 静的 をコンストラクタで実行します。
public class Service : IService
{
private readonly ISomeDependency dep;
public Service(ISomeDependency dep)
{
if (dep == null)
{
throw new ArgumentNullException("dep");
}
this.dep = dep;
}
public ISomeDependency Dependency
{
get { return this.dep; }
}
}
Serviceクラスがどのように不変性を保証しているかに注目してください。インスタンスが作成されると、Guard Clause と
readonly
というキーワードがあります。
短命のオブジェクトが必要な場合は、抽象ファクトリーを使用します。
コンストラクタ注入で注入される依存関係は長寿命になる傾向がありますが、時には短命のオブジェクトが必要になったり、実行時にしか分からない値に基づいて依存関係を構築したりすることがあります。
参照 これ をご覧ください。
最後の責任ある瞬間にのみ作曲する
最後の最後までオブジェクトを非連結にする。通常、アプリケーションのエントリポイントでは、すべてを待って配線することができます。これを コンポジションルート .
詳しくはこちら
Facadeを使った簡略化
もし、出来上がったAPIが初心者のユーザーにとって複雑すぎると感じたら、いつでも、いくつかの ファサード クラスは、一般的な依存関係の組み合わせをカプセル化したものです。
柔軟で発見力の高いFacadeを提供するために、Fluent Buildersを用意することも考えられる。こんな感じ。
public class MyFacade
{
private IMyDependency dep;
public MyFacade()
{
this.dep = new DefaultDependency();
}
public MyFacade WithDependency(IMyDependency dependency)
{
this.dep = dependency;
return this;
}
public Foo CreateFoo()
{
return new Foo(this.dep);
}
}
これは、ユーザーがデフォルトのFooを作成するために、次のように記述することを可能にします。
var foo = new MyFacade().CreateFoo();
しかし、カスタムの依存関係を供給することが可能であることは非常に発見的であり、次のように書くことができるでしょう。
var foo = new MyFacade().WithDependency(new CustomDependency()).CreateFoo();
MyFacadeクラスが多くの異なる依存関係をカプセル化すると想像すると、拡張性を発見できるようにしながら、適切なデフォルトを提供する方法が明らかになるかと思います。
参考までに、この回答を書いたずっと後に、ここに書かれているコンセプトを発展させ、次のような長いブログ記事を書きました。 DIフレンドリーなライブラリ についての記事と DIフレンドリーフレームワーク .
関連
-
[解決済み】"出力タイプがクラスライブラリのプロジェクトは直接起動できない"
-
[解決済み】GDI+、JPEG画像をMemoryStreamに変換する際にジェネリックエラーが発生しました。
-
[解決済み】ここで「要求URIに一致するHTTPリソースが見つかりませんでした」となるのはなぜですか?
-
[解決済み】WebForms UnobtrusiveValidationModeは、jqueryのScriptResourceMappingを必要とする
-
[解決済み】文字列が有効な DateTime " format dd/MM/yyyy " として認識されなかった。
-
[解決済み] Spring Frameworkの@Injectと@Autowiredの違いは何ですか?どのような条件でどちらを使うか?
-
[解決済み] Inversion of ControlとDependency Injectionの比較
-
[解決済み] なぜ依存性注入を使用するのですか?
-
[解決済み] Dependency Injectionのコンストラクタの狂気を回避する方法とは?
-
[解決済み】NodeJSで依存性注入は必要ですか、それともどう対処すれば・・・?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】パディングが無効で、削除できない?
-
[解決済み】C# ASP.NET使用時に「WebClientのリクエスト中に例外が発生しました。
-
[解決済み】なぜこのコードはInvalidOperationExceptionを投げるのですか?
-
[解決済み】Moqを使用してメソッド呼び出しを検証する
-
[解決済み】値をNULLにすることはできません。パラメータ名:source
-
[解決済み】5.7.57 SMTP - MAIL FROMエラー時に匿名メールを送信するためにクライアントが認証されない
-
[解決済み】aspNetCore 2.2.0 - AspNetCoreModuleV2 エラー
-
[解決済み】エラー「必要なフォーマルパラメータに対応する引数が与えられていない」を解決する?
-
[解決済み】パラメータ付きRedirectToAction
-
[解決済み] DIコンテナを介して作成されたオブジェクトを初期化するパターンはありますか?