Как создать построитель в C # для объекта, свойства которого являются ссылочными типами?

StackOverflow https://stackoverflow.com/questions/1402975

Вопрос

Я начал создавать конструктор, чтобы легко создавать тестовые данные для написанных модульных тестов.

Базовая структура строителя:

public class MyClassBuilder
{
    public int id = 0; //setting the default value here

    //allows MyClass to be built with a specific id
    public MyClassBuilder WithId(int id)
    {
        this.id = id;
        return this;
    }

    public MyClass Build()
    {
        return new MyClass(id);
    }
}

Использование этого шаблона становится следующим:

MyClass mc = new MyClassBuilder().WithId(5).Build();

Мне это удобно ... но у меня есть вопросы, когда MyClass имеет свойство, которое не является тривиальным .... Я немного не уверен в том, как приступить к созданию это со значением по умолчанию.

public class MyClassBuilder
{
    public int id = 0; //setting the default value here

    //do I construct the default value using a MySecondClassBuilder?
    public MySecondClass mySecondClass;

    //allows MyClass to be built with a specific id
    public MyClassBuilder WithId(int id)
    {
        this.id = id;
        return this;
    }

    public MyClassBuilder WithMySecondClass(MySecondClass mySecondClass)
    {
        this.mySecondClass = mySecondClass;
    }

    public MyClass Build()
    {
        return new MyClass(id);
    }
}

Я предполагаю, что я бы создал конструктор для MySecondClass и использовал его для создания реализации по умолчанию.

Может ли кто-нибудь подтвердить, что мое предположение верно и является наилучшей практикой?

В настоящее время я проверяю свое предположение, но я решил документировать эту идею в StackOverflow, поскольку единственные примеры паттерна для разработчиков, которые я смог найти, когда-либо создавались в Google, - это только свойства, которые являются типами значений, а не ссылочные типы.

Это было полезно?

Решение

Как с большинством вещей - это зависит.

Если вы хотите ссылочную семантику в поле mySecondClass (то есть: вы хотите сохранить ссылку на другой класс), то это точно так же, как ваше целое число. Значение по умолчанию, равное нулю, может быть вполне приемлемым.

Однако, если вы хотите всегда гарантировать значение, вам нужно либо создать, либо просто создать новый объект для вашего второго класса.

Кроме того, если вы хотите клонировать, а не по ссылочным копиям, вам нужно создать новый объект и назначить его для ссылки.

Тем не менее, во многих случаях традиционные конструкторы являются более подходящими, чем попытка создать свободный интерфейс в стиле сборки. Это действительно легко "испортить" свободный интерфейс для создания подобного, так как вы полагаетесь на пользователя больше, чем на традиционный конструктор.

В качестве примера, в вашем коде, что происходит, если пользователь никогда не вызывает Build? Он по-прежнему что-то возвращает (так как каждый из методов возвращает объект), но допустимо ли это? Я не был бы уверен как потребитель вашего класса. Традиционные конструкторы с перегрузками, с другой стороны, показывают мне, что действительно, а что нет, и применяются во время компиляции.

Другие советы

Как только у меня появится сложный объект, в котором я хочу использовать пустышку в модульных тестах, я обычно обращаюсь к фальсификации / подделке / изоляции. В C # я предпочитаю Moq, но есть несколько таких, как Rhino Mocks, Typemock и так далее.

Преимущество заключается в том, что они, как правило, имеют возможность заглушить все свойства, существующие в исходном типе, со значениями по умолчанию и пустыми объектами, без необходимости делать что-либо, кроме оператора одной строки, для создания поддельного объекта. В то же время вы можете легко настроить объект так, чтобы он возвращал значения, которые вы хотите для свойств, имеющих значение для вашего теста. Кроме того, большинство таких фреймворков поддерживают рекурсивное подделывание, так что сложные объекты внутри вашего типа также будут поддельными и т. Д.

Есть причины, по которым кто-то может не захотеть использовать отдельную платформу, и в этом случае я думаю, что предложение Рида Копси было бы ручным способом сделать это.

Если нет причин не добавлять фреймворк (который будет зависеть только от ваших тестовых проектов, если вы разделите тестирование), я бы искренне рекомендовал его для сложных типов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top