5

テストのデータ読み込みを支援する流暢なビルダー スタイル パターンを作成しました。特定のメソッドの順序は重要であり、正しい順序を管理するための推奨される方法は何か疑問に思っていました。

私は現時点で以下を持っています:

using NUnit.Framework;

[TestFixture]
public class DataBuilderTests
{
    [Test]
    public void Can_NAME()
    {
        new DataLoader()
            .Start() // must be called first
            .Setup() // then called next
            .LoadEmployees() // optional order not NB
            .LoadProducts() // optional order not NB
            .StartCleanup() // begin cleanup
            .CleanupEmployees() // optional order not NB
            .CleanupProducts() // optional order not NB
            .End();
    }
}

public class DataLoader
{
    public DataBuilderSetup Start()
    {
        return new DataBuilderSetup(this);       
    }
}

public class DataBuilderSetup
{
    private readonly DataLoader _dataLoader;

    public DataBuilderSetup(DataLoader dataLoader)
    {
        _dataLoader = dataLoader;
    }

    public DataBuilderOptions Setup()
    {
        // do setup
        return new DataBuilderOptions(_dataLoader);
    }
}

public class DataBuilderOptions
{
    private readonly DataLoader _dataLoader;

    public DataBuilderOptions(DataLoader dataLoader)
    {
        _dataLoader = dataLoader;
    }

    public DataBuilderOptions LoadEmployees()
    {
        // load
        return this;
    }

    public DataBuilderOptions LoadProducts()
    {
        // load
        return this;
    }

    public DataBuilderCleanupOptions StartCleanup()
    {
        return new DataBuilderCleanupOptions(_dataLoader);
    }
}

public class DataBuilderCleanupOptions
{
    private readonly DataLoader _dataLoader;

    public DataBuilderCleanupOptions(DataLoader dataLoader)
    {
        _dataLoader = dataLoader;
    }

    public DataBuilderCleanupOptions CleanupEmployees()
    {
        // cleanup
        return this;
    }

    public DataBuilderCleanupOptions CleanupProducts()
    {
        // cleanup
        return this;
    }

    public DataLoader End()
    {
        return _dataLoader;
    }
}
4

5 に答える 5

4

Java (C# とその多重継承によって違いはありません) では、次のようにすることができます。

1 つのメソッドのみを含むインターフェイスのセットを宣言します。

Interface DoFirstThing { // could be renamed to "BuilderOnStart" or "BuilderStartingState"
    DoSecondThing doFirst();
}

Interface DoSecondThing {
    DoLastThing doSecond();
}

Interface DoLastThing {
    BuilderReady doLast();
}

Interface BuilderReady {
    Result build();
}

class BuilderWithForcedSequence implements DoFirstThing, DoSecondThing, DoLastThing, BuilderReady {

     // implement all

}

最後に、そのビルダーの初期状態を設定するためのファクトリまたはファクトリ メソッドが必要になります。

public DoFirstThing createNewBuilderWithForcedSequence(requiredParameters){
    return new BuilderWithForcedSequence(requiredParameters);
}

これにより、ビルド メソッドの順序付けが強制された Builder が生成されます (意味のある名前に変更する必要がありますdoThat) 。doFirst()doSecond()build()

Result result = builder.doFirst().doSecond().doLast().build();


編集:
おっと、それはあなたのアプローチとまったく同じです:)

于 2012-08-31T11:26:47.637 に答える
2

BuilderPattern の強みの 1 つは、メソッド呼び出しの強制的な「魔法の」順序付けから消費者を保護できることです。

次のいずれかになるように設計を変更することをお勧めします。

  • Startおよびへの強制的な順序付けされた呼び出しからコンシューマを保護するために、必要なすべての引数が前もって提供されますSetup
  • エンティティの責任を変更して、任意に構築できるようにします。

明らかに、これは私の個人的な好みです。この型がサード パーティによって使用されるライブラリの一部を形成する場合は、マジック メソッドの順序付けの必要性を取り除くことを強くお勧めします。これが社内でのみ使用される可能性が高い場合は、コードの変更に関連するコストと変更しない場合のコストを比較検討する必要があります。

于 2012-08-31T09:40:58.233 に答える
1

好ましい方法は、何としてもそれを避けることです。何をする必要があるかが明確になるようにビルダーを設計します。

ObjectBuilder
.Init()
.Optional1()
.Optional3()
.Optional2()
.ToObject()

何かを最初に行う必要がある場合は、コンストラクタまたはファクトリ メソッドでこれを行います。次に、ビルド プロセス、クリーンアップ、およびすべてを完了する 1 つのメソッドを常に用意します。

于 2012-08-31T09:40:25.830 に答える
1

たとえば、プライベート キュー メンバーをビルダーにQueue<string>追加し、すべてのビルダー ステップで操作の名前を追加できます。

.Build()メソッドまたはあなたの場合.End()、正しい操作名が正しい順序で含まれているかどうかをキューをチェックします。そうでない場合は、投げることができますInvalidOperationException

また、ツリーをデータ構造として使用することもできます。ツリーを使用すると、以前のビルダー ステップでは利用できないオプションを分析できます。

ただし、私のアプローチは実際にはハックであり、メンテナンスの問題が発生するため、他の回答を検討することをお勧めします。

于 2012-08-31T09:40:37.417 に答える
0

あなたの現在の解決策は、流暢な構文を提供するために私が採用するアプローチですが、必ずしもビルダーのパターンに正確に従っているとは言えません。基本的に、あなたがしていることは、ステートマシンによって提供される制限とともにビルダーをチェーンすることです。流暢な休止状態や流暢なアサーションなど、他の一般的に受け入れられている流暢な構成との違いはほとんどありません。

于 2012-08-31T21:13:27.470 に答える