2

Is it possible to write a TestDataBuilder which follows a given syntax?

So for example:

Carbuilder

I know how to write a basic builder for a car that's not the problem.

But how can I achieve, that I can only add new windows to a door?

So this is allowed:

var car = CarBuilderWithSyntax.Create()
              .WithDoor()
                  .HavingSide(Sides.Left)
                  .WithWindow()
                      .HavingWidth(50)
                      .HavingHeight(50)
            .Build();

But this is not allowed:

var car = CarBuilderWithSyntax.Create()
              .WithWindow()
                  .HavingWidth(50)
                  .HavingHeight(50)
          .Build();

Is there a possibility to enforce this syntax-rule?

Can this be achieved by using an additional door builder which inherits car builder?

Should the car builder implement different interfaces like IDoorBuilderWithSyntax which defines the methods ICarBuilderWithSyntax WithWindow() and ICarBuilderWithSyntax HavingSide(); ICarBuilderWithSyntax HavingColor()?

4

1 回答 1

2

您可以执行以下操作:

public enum Sides
{
    Left,
}

public class Car
{

}

public class CarBuilderWithSyntax
{
    protected CarBuilderWithSyntax ParentBuilder { get; private set; }

    public static CarBuilderWithSyntax Create()
    {
        return new CarBuilderWithSyntax(null);
    }

    protected CarBuilderWithSyntax(CarBuilderWithSyntax parent)
    {
        ParentBuilder = parent;
    }

    protected CarBuilderWithSyntax GetParentBuilder()
    {
        CarBuilderWithSyntax parentBuilder = this;

        while (parentBuilder.ParentBuilder != null)
        {
            parentBuilder = parentBuilder.ParentBuilder;
        }

        return parentBuilder;
    }

    public DoorBuilder WithDoor()
    {
        return new DoorBuilder(GetParentBuilder());
    }

    public CarBuilderWithSyntax WithEngine(int cmq)
    {
        if (ParentBuilder != null)
        {
            return GetParentBuilder().WithEngine(cmq);
        }

        // Save somewhere this information
        return this;
    }

    public Car Build()
    {
        return null;
    }

    public class DoorBuilder : CarBuilderWithSyntax
    {
        public DoorBuilder(CarBuilderWithSyntax builder)
            : base(builder)
        {
        }

        protected new DoorBuilder GetParentBuilder()
        {
            DoorBuilder parentBuilder = this;

            while ((parentBuilder.ParentBuilder as DoorBuilder) != null)
            {
                parentBuilder = parentBuilder.ParentBuilder as DoorBuilder;
            }

            return parentBuilder;
        }

        public DoorBuilder HavingSide(Sides side)
        {
            // Save side this information somewhere
            return GetParentBuilder();
        }

        public WindowBuilder WithWindow()
        {
            return new WindowBuilder(this);
        }

        public class WindowBuilder : DoorBuilder
        {
            public WindowBuilder(DoorBuilder builder)
                : base(builder)
            {
            }

            public WindowBuilder HavingWidth(int width)
            {
                // Terminal elements don't need to do the GetParentBuilder()
                return this;
            }

            public WindowBuilder HavingHeight(int width)
            {
                // Terminal elements don't need to do the GetParentBuilder()
                return this;
            }
        }
    }
}

现在您只需要选择如何/在哪里保存Builder...的信息。注意各种类如何互连,以及各种GetParentBuilder()用途。

var car = CarBuilderWithSyntax.Create()
  .WithDoor()
      .HavingSide(Sides.Left)
      .WithWindow()
          .HavingWidth(50)
          .HavingHeight(50)
  .WithEngine(100)
  .Build();
于 2015-05-22T12:27:26.680 回答