依存性注入とランタイムオブジェクトの作成
-
03-07-2019 - |
質問
依存性注入の原則に従うことを試みましたが、この記事を読んだ後、何か間違ったことをしていることがわかりました。
私の状況は次のとおりです。私のアプリケーションはさまざまな種類の物理メールを受信します。すべての受信メールは、 MailFunnel
オブジェクトを通過します。
実行中、 MailFunnel
は外部からさまざまな種類のメッセージを受け取ります:Box、Postcard、Magazine。
各メールタイプは、異なる方法で処理する必要があります。たとえば、Boxが入った場合、配送する前に重量を記録する必要があります。したがって、 BoxHandler
、 PostcardHandler
、および MagazineHandler
オブジェクトがあります。
新しいメッセージが私の MailFunnel
に入るたびに、 new に対応する MailHandler
オブジェクトをインスタンス化します。
例:
class MailFunnel { void NewMailArrived( Mail mail ) { switch (mail.type) { case BOX: BoxHandler * bob = new BoxHandler(shreddingPolicy, maxWeightPolicy); bob->get_to_work(); break; case POSTCARD: PostcardHandler * frank = new PostcardHandler(coolPicturePolicy); frank->get_to_work(); break; case MAGAZINE: MagazineHandler * nancy = new MagazineHandler(censorPolicy); nancy->get_to_work(); break; } } private: MaxWeightPolcy & maxWeightPolicy; ShreddingPolicy & shreddingPolicy; CoolPicturePolicy & coolPicturePolicy; CensorPolicy & censorPolicy; }
一方で、これは素晴らしいことです。なぜなら、5つの異なるメールを受け取ると、すぐに5つの異なる MailHandlers
が同時に動作してビジネスの世話をするからです。ただし、これは Iオブジェクトの作成とアプリケーションロジックの混合-依存性注入に関しては大したことはありません。
また、 MailFunnel
が実際に必要としない MailFunnel
オブジェクトにこれらすべてのポリシー参照がぶらぶらしています。 MailFunnel
がこれらのオブジェクトを持っている唯一の理由は、それらを MailHandler
コンストラクターに渡すことです。繰り返しになりますが、これも避けたいものです。
すべての推奨事項を歓迎します。ありがとう!
解決
これは、私にとっては工場のように見えます。 get_to_work()メソッドの呼び出しを呼び出しから移動し、ハンドラーを返します。このパターンは、ファクトリーでかなりうまく機能します。
class MailHandlerFactory
{
IMailHandler* GetHandler( Mail mail )
{
switch (mail.type)
{
case BOX:
return new BoxHandler(shreddingPolicy, maxWeightPolicy);
break;
case POSTCARD:
return new PostcardHandler(coolPicturePolicy);
break;
case MAGAZINE:
return new MagazineHandler(censorPolicy);
break;
}
}
private:
MaxWeightPolcy & maxWeightPolicy;
ShreddingPolicy & shreddingPolicy;
CoolPicturePolicy & coolPicturePolicy;
CensorPolicy & censorPolicy;
}
class MailFunnel
{
MailHandlerFactory* handlerFactory;
MailFunnel( MailHandlerFactory* factory ) {
handlerFactory = factory;
}
void NewMailArrived( Mail mail ) {
IMailHandler handler = handlerFactory.GetHandler(mail);
handler.get_to_work();
}
}
他のヒント
そのswitchステートメントが表示されたら、ポリモーフィズムを考えてください。この設計は、変更によってのみ拡張できます。クラスを追加して新しい動作を追加できるような方法でやり直します。それが、オープン/クローズド原則のすべてです。
さまざまな種類のメールを受け取るオーバーロードされた3つのメソッドがあり、適切な処理を実行できないのはなぜですか?または、各タイプにそれ自身を処理させます。
実際、タイプのようなものがある場合、実際には異なるタイプを持つべきです。
基本的に次のことを行います。
1)Mailクラスを抽象化します。
2)メール、Box、PostCard、およびMagazineの3つのサブクラスを作成します
3)各サブクラスにメールを処理するメソッドを提供するか、個別のHandlerFactoryに集中化する
4)メールファンネルに渡されたら、ハンドルメールメソッドを呼び出すか、HandlerFactoryにメールを渡して適切なハンドラーを返させます。繰り返しますが、どこにでも厄介なswitchステートメントを置くのではなく、言語を使用してください。これが型とメソッドのオーバーロードの目的です。
メール処理が複雑になり、それを削除したい場合は、最終的にメールハンドラクラスを作成し、その中にそれらのポリシーを抽出できます。
テンプレートメソッドの使用を検討することもできます。これらのそれぞれの唯一の本当の違いはインスタンスハンドラであるように見えるため、メールタイプがハンドラを決定するように単純化することができます。基本的に同じです。
C ++プロジェクトに依存性注入を適用していることに興味があります。他の場所で行われているため、Googleで簡単に検索すると、Googleコードプロジェクト Autumn Framework が見つかります。
しかし、tvanfossonの答えは、新しいフレームワークを採用する前に、まず試してみることをお勧めします。