Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the preferred way to managing order in the builder pattern?

I have created a fluent builder style pattern for helping with data loading my tests. The order of certain methods is important and was wondering what the preferred method to managing the correct sequence is.

I have the following at the moment:

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;
    }
}
like image 593
Samuel Goldenbaum Avatar asked Aug 31 '12 09:08

Samuel Goldenbaum


1 Answers

In Java (C# and its multiple inheritance shouldn't make it any different) you could do it that way:

declare set of interfaces, that contain one method only:

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

}

and finally you would need some factory or factory method to set the initial state for that builder:

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

This would produce Builder, with forced ordering of building methods (they should be renamed from doThat to something meaningful), that can call only doFirst(), after that doSecond() ... and so on, till final state, when obiect would be build, using build() method.

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


EDIT:
Oops, that's pretty exact your approach :)

like image 199
dantuch Avatar answered Sep 27 '22 21:09

dantuch