8

特定のデータまたは別のオブジェクトを渡してオブジェクトのインスタンスを作成したいが、データまたはオブジェクトが有効であるか、正しい状態である必要があるという状況によく遭遇します。これを行う「正しい」方法について、私はいつも少し不明確です。これが私の例です:

このクラスを考えると:

class BusinessObject()
{
    const Threshold = 10;

    public BusinessObject(SetOfData<SomeType> setofdata)
    {
        // an example of some validation
        if (setofdata.count > Threshold)
        {
            // performance some business logic
            // set properties
        }
    }
}

これを行うと、いくつかの問題が発生する可能性があります。

var setofdata = new SetOfData<SomeType>();

// if data is not valid then the object will be created incorrectly
var businessObject = new BusinessObject(setofdata);

したがって、私の解決策は常に次のいずれかでした。

class BusinessObjectBuilder()
{
    public BusinessObject Build(SetOfData<SomeType> setofdata)
    {
        // an example of some validation
        if (setofdata.count > Threshold)
            return new BusinessObject(setofdata);
        }
        else
        {
            return null;
        }
    }
}

または、コンストラクタをプライベートにして、静的ファクトリ メソッドを追加します。

class BusinessObject()
{
    const Threshold = 10;

    public static Create(SetOfData<SomeType> setofdata)
    {
        if (setofdata.count > Threshold)
        {
            return new BusinessObject(setofdata);
        }
        else
        {
            return null;
        }
    }

    private BusinessObject(SetOfData<SomeType> setofdata)
    {
        // performance some business logic
        // set properties
    }
}

理想的には、1 つのプロセスで複数のビジネス オブジェクトが作成されている可能性があるため、データが無効な場合に例外をスローしたくありません。

また、Abstract Factory または Factory メソッドについて私が読んだすべての例では、何らかの型または列挙型を渡し、正しいオブジェクトを構築して返す必要があります。彼らはこのシナリオをカバーしていないようです。

では、このシナリオの規則は何ですか? アドバイスをいただければ幸いです。

4

5 に答える 5

11

IMHOコンストラクターの検証は、指定されたパラメーターが設定されていない限り、オブジェクトを作成できないことを確認する必要がある多くの状況に最適です。

public class BusinessObject
{
    const Threshold = 10;

    public BusinessObject(SetOfData<SomeType> setofdata)
    {
        // an example of some validation
        if (setofdata.count > Threshold)
        {
            throw new InvalidOperationException("Set data must be above treshold");
        }
    }
}

ただし、次の場合、これは不適切な実装になります。

  • 下書き状態などの無効なオブジェクトがある場合があります。
  • デフォルトのコンストラクターが必要な場合に ORM で使用されます
  • 重い検証ロジックが発生した場合。

ポイント1と2については、リクエスト - 検証 - 送信メカニズム以外のオプションは提案できません。

ポイント 3 については、その理由は、クラスがバリデーション自体とモノリシック コードの作成に多くのことを行うためです。検証ロジックが多い場合は、バリデーターを注入してビルダーパターンを実装し、BusinessObject内部のコンストラクターを作成することをお勧めします。

public class BusinessObjectBuilder
{
    public BusinessObjectBuilder(IBusinessObjectValidator validator){
        this.validator = validator;
    }
    IBusinessObjectValidator validator;

    public BusinessObject Build(SetOfData<SomeType> setofdata)
    {
        // an example of some validation
        if (validator.IsValid(setofdata))
            return new BusinessObject(setofdata);
        }
        else
        {
            throw new //exception
        }
    }
}

これにより、モジュラー プログラミングが強制され、モノリシック コードが防止されます。

両方のコードは次のとおりです。

  • テストしやすい
  • 見直しやすい
  • 拡張可能
于 2013-05-14T10:41:53.723 に答える
1

「正しい」方法はわかりません。しかし、私はあなたに私のやり方を伝えることができます =)

私ならファクトリーパターンを選びます。検証エラーが原因でアプリケーションを中止したくない場合は、ファクトリが障害のある部分にデフォルト値を入力できます。

于 2013-05-14T10:25:42.000 に答える
1

Create引数が正しくない場合など、メソッドから例外をスローするのが一般的な方法だと思います。nullこのシナリオに戻り、フロー制御に例外を使用しないようにすることについて、あなたは留保しています。あなたは単に持つことができます:

public bool CanBuild(SetOfData<SomeType> setofdata)
{
    return validator.IsValid(setofdata);
}

public BusinessObject Build(SetOfData<SomeType> setofdata)
{
    if (validator.IsValid(setofdata))
    {
        return new BusinessObject(setofdata);
    }
    throw new ArgumentException();
}

setofdataで検証されたという保証がないため、例外をスローしたままにしCanBuildます。これにより、フロー制御に例外を使用することを回避できますが、検証が 2 回行われるという欠点があります。二重の検証をなくすには、 のTryCreate代わりに または の横に置きCreateます。署名を見るだけで、ビジネス オブジェクトの作成とは別に、このメソッドは入力データの検証を実行し、この検証の結果を例外以外の形式で返すことがわかります。(int.Parseおよびを参照int.TryParse)

public bool TryBuild(SetOfData<SomeType> setofdata, out BusinessObject businessObject)
{
    if (validator.IsValid(setofdata))
    {
        businessObject = new BusinessObject(setofdata);
        return true;
    }
    businessObject = null;
    return false;
}

この検証メソッドは、検証を含まない他のコンストラクターにアクセスできないコンストラクターを呼び出しますが、広くアクセス可能なすべてのコンストラクターは引き続き検証し、例外をスローします。

もちろん、メソッドBuiltとメソッドTryBuiltは ( のように) 静的にintすることも、ファクトリ パターンを適用することもできます。

于 2013-05-14T21:30:26.717 に答える