質問
(存在する場合)暗黙の仮定または制限と設計の違いは次のとおりです:
A)これ:
class SampleClass1
{
IWorker workerA;
IWorker workerB;
void setWorkerA(IWorker w);
void setWorkerB(IWorker w);
WorkResult doWork();
}
B)対これ:
class SampleClass2
{
WorkResult doWork(IWorker workerA, IWorker workerB);
}
特定のプロジェクトに依存することはわかっていますが、上記のクラスが小さなフレームワークの一部である場合はどうなりますか?最初のクラスは状態を維持し、ステップをより自然に分離できますが、2番目のクラスは「リアルタイムコミュニケーション」を保証します。 doWork()が呼び出されるたびにWorkerが渡されるため、外部の呼び出し元により自然になります。
上記の2つの方法の選択をガイドする推奨される使用法または一般的なプラクティスはありますか?ありがとう。
解決
オプション(A)では、関数オブジェクトまたはファンクターと呼ばれるものを作成しています。これは、よく文書化されている。
2つの主な利点は次のとおりです。
- ワーカーを1か所で設定してから、オブジェクトを他の場所で使用することができます
- オブジェクトは呼び出し間で状態を保持できます
また、依存性注入フレームワーク(Spring、Guiceなど)を使用している場合、ファンクターは自動的に初期化され、必要な場所に注入されます。
関数オブジェクトは、ライブラリで広く使用されています。 C ++標準テンプレートライブラリ
他のヒント
SampleClass1
- doWork間でワーカーの状態を維持する必要がある場合があります
- ワーカーを個別に設定する機能が必要になる場合があります。 (doWork 1と2、次に2と3)
- 同じワーカーでdoWorkを複数回実行することが予想されるため、ワーカーを維持したい。
- 私はユーティリティクラスではありません。私のインスタンスが重要です。
SampleClass2
- 2人の労働者をください。一緒に仕事をします。
- 私は彼らが誰であるかを気にしませんし、彼らを維持したくないです。
- ワーカー間のペアリングを維持するのは、他の誰かの仕事です。
- 私はユーティリティクラスに近いかもしれません。たぶん静的になります。
別のオプション、ケースAのバリアントは次のとおりです。
class SampleClass3 { SampleClass3( IWorker workerA, IWorker workerB ); WorkResult doWork(); }
利点:
-
(ケースAとは対照的に)建設時に必要なすべての労働者を提供する必要があるため、オブジェクトに欠陥を作ることは困難です。
-
SampleClass3および/またはいずれかのワーカー内で状態を保持できます。 (これはケースBでは不可能です。)
欠点:
- SampleClass3を構築する前に、後で提供するのではなく、すべてのワーカーを準備しておく必要があります。もちろん、セッターを提供して、後で変更できるようにすることもできます。
複数のメソッドがIWorker aとIWorker bに依存している場合、サンプルAを実行します。
doWork()のみがIWorker aとIWorker bの両方を使用する場合、サンプルBを実行します。
また、SampleClassの本当の目的は何ですか? doWorkは、他の何よりもユーティリティメソッドmroeに少し似ています。
A)は、オブジェクトに欠陥がある可能性があるため(1つまたは両方のワーカークラスが設定されていない可能性があるため)、設計が不適切です。
B)良いことがあります。ただし、SampleClass2の内部状態に依存しない場合は静的にします
別のオプション:
IWorkerクラス:
static WorkResult doWork(Iworker a、Iworker b);
IMOの2番目のアプローチは見栄えがよく、呼び出し元がタスクを実行するために使用するコードを少なくする必要があります。 2番目のアプローチではエラーが発生しにくく、呼び出し側はオブジェクトが完全に初期化されないことを心配する必要はありません。
代わりに、単に WorkResult
を返し、個々のクラスが実装方法を決定しますか?このように、あなたは時期尚早の決定に自分自身を制限しません。