web-dev-qa-db-ja.com

拡張性に関する設計の質問

Webサービスからの要求を処理するクラスの決定を処理する新しいクラスを構築しています。この新しいクラスの拡張性に関して私が抱えている問題の解決策を探しています。各リクエストは異なる方法で処理され、それらを処理するためのロジックはそれぞれ独自のクラスにあります。私が解決したいと思っている問題は、新しいタイプのリクエストを追加するときに既存のコードを変更する必要がないようにクラスを設計する方法です。私が以下に持っているコードを考えてみてください。次の例のタイプミスはご容赦ください。

public interface IRequestData
{

}

public class OldRequestData : IRequestData
{
    // Some properties holding data.
}

public class NewRequestData : IRequestData
{
    // Some properties holding data.
}

public class ProcessOldRequestData
{
    public void Process(OldRequestData Data)
    {
        // Some code to process the request.
    }
}

public class ProcessNewRequestData
{
    public void Process(NewRequestData Data)
    {
        // Some code to process the request.
    }
}

public class RequestProcessor
{
    public void ProcessRequest(IRequestData Data)
    {
        // Get and load base type of Data

        // Based on if it's OldRequestData, NewRequestData, or *FutureRequestData*,
        // Instantiate the appropriate class to process the request.
    }
}

これは私が現在使用しているモデルです。問題は、新しいタイプのリクエストごとに、新しいクラスを呼び出すためにRequestProcessorを変更する必要があることです。このクラスに、各タイプの要求を処理するために呼び出す必要のあるクラスを「認識」させる方法はありますか?これを処理するより良いものがあれば、私は他の提案を非常に受け入れます。

よろしくお願いします。

1
Tama198

それを行うには2つの方法があります。

  1. OO方法:現在のOldRequestDataクラスとNewRequestDataクラスをよりアクティブにし、them目的の動作を実行するメソッドを実装します。これは、Processメソッドが配置されることを意味します。 IRequestDataクラスに追加できます。利点は、クラスにIRequestDataを実装し、対応するProcessメソッドを実装させることができることです。ここでの欠点は、Processクラスごとに異なる種類のIRequestDataメソッド(たとえば、2つ)が必要になるとすぐに発生します。 OldRequestDataを処理するさまざまな方法とNewRequestDataを処理する2つの異なる方法)

  2. 最初の解決策の欠点を解決するということは、 Expression Problem に飛び込むことを意味します(ここでは動的に型指定された言語を使用していますが)。これを解決するにはさまざまな方法がありますが、それらはより複雑になります。複雑さに対してメリットを重視する必要があります。 IRequestDataクラスが必要ない場合は、最初のソリューションを使用する必要があります。

0
valenterry

オブジェクトへのリクエストのコレクション(マップ、辞書など)を作成します。 ProcessRequestでは、コレクションを反復処理して入力要求に一致するエントリを見つけ、関連するオブジェクトを呼び出します。

次に、コレクションにデータを入力するだけで済みますが、これは、構成を読み取るか、起動時に各RequestDataクラスにそれ自体を登録させることによって(処理できる一連の要求とと​​もにコレクションに追加することによって)行うことができます。

もちろん、カスタムロジックを使用して新しい「FutureRequestData」クラスを作成する必要がある場合は、コードを更新する必要があります。 configから読み取られた任意のコード(スクリプト言語など)を実行し、このコードを実行させることができるエンジンまたはコンパイラがない限り、それを回避することはできません。

4
gbjbaanb

Abstract factoryBuilder および Factory メソッドパターンの使用を見てください。

これらにより、以下のようなことができます(構文エラーについてはお詫びします)。

IRequestData rd = RequestDataBuilder.Build('old').GetData();
// not strictly necessary but follow the pattern throughout
IRequestProcessor rp = RequestProcessorBuilder.Build().GetProcessor();

あなたが今できること

rp.ProcessRequest(rd);

作業しているデータまたはプロセッサの(古いまたは新しい)セットを知らずに、または気にせずに。

RequestProcessorBuilderは、Build()メソッドに渡された引数、またはビルダーが使用するその他のパラメーターに基づいて、ビルドする要求プロセッサーを判別できます。

したがって、デフォルトは「速い」ProcessSpeedである可能性がありますが、「遅い」速度を指定することもできます。その場合、別のオブジェクトが返されます。重要なのは、呼び出された人はインターフェースと相互作用するだけなので、気にしないということです。

IRequestProcessor rp = RequestProcessorBuilder.Build()
                         .ProcessSpeed('slow') 
                         .GetProcessor();

または、ビルダーが返すオブジェクトに関する決定は、config(file、db、whereever)から行うことができます。

それらのリンク(例があります)から、簡単な説明:

  • 抽象ファクトリ:具体的なクラスを指定せずに、関連オブジェクトまたは依存オブジェクトのファミリを作成するためのインターフェイスを提供します
  • ビルダー:複雑なオブジェクトの構築をその表現から分離し、同じ構築プロセスでさまざまな表現を作成できるようにします
  • ファクトリメソッド:単一のオブジェクトを作成するためのインターフェイスを定義しますが、インスタンス化するクラスをサブクラスに決定させます。ファクトリメソッドを使用すると、クラスはインスタンス化をサブクラスに延期できます
0
nwahmaet