Тааааааааааааааааааааааааааааааааааааааааааааааааааааа?
Это "утилитарный" класс, который помогает вам в процессе создания объекта... Или чего-то еще, что он должен строить.

Простой (и очень глупый) пример был бы полезен. Представьте, что вы хотите создать строку приветствия для пользователя. И вы хотите сделать это через fluent builder. Это должно выглядеть примерно так:

Builder.use().english().greet('Bob').build();
// produces: 'Hello, Bob'
Builder.use().spanish().greet('Bob').build();
// produces: 'Hola, Bob'

Итак, мы хотим абстрагировать часть hello/hola, а также нам нужна некоторая логика проверки для параметра имени. Скажем, минимум 3 символа. Этот построитель примеров генерирует строку, но вы также можете создать ее для объектов. Это очень хороший способ централизовать логику проверки и направить пользователя (другого разработчика) в том, как создавать конкретные экземпляры.

Эффект держания за руку

Когда вы создаете класс с методом, когда вы ставите точку в этом классе, intelisense должен перечислить вам доступные вещи.

Однако трюк, которого я хочу достичь, заключается в том, чтобы связывать и сокращатьметодыварианты по мере продвижения. В приведенном выше примере класс строителя должен иметь только доступный метод use(). После этого только english() или spanish() и, наконец, greet(), за которым следует build(). build() в этом сценарии является излишним, но это обычное соглашение для обозначения окончания процесса сборки.

Еще одна незначительная вещь. Обратите внимание, что я не создавал экземпляр Builder . новоеключевое слово не требовалось. Так как же всего этого добиться? Интерфейсы.

Проектирование шага

Для каждого шага и возможных вариантов выбора нам нужен интерфейс. Итак, шаги были такими:

За исключением use() (я перейду к нему через минуту), все остальные коробки имеют интерфейс. Код:

Здесь вы можете увидеть прогресс. Мы начинаем с ILanguage, где все функции указывают на следующий шаг: IGreet, который снова указывает на IBuild. Класс Builder должен реализовать их все. Таким образом, вы можете вернуть экземпляр Builder, который будет автоматически приведен к определенному интерфейсу и его набору функций... Предоставляя вам контроль над потоком.

Это требует немного времени и практики, чтобы обернуть голову, но это не так сложно.

Наконец, я хочу поговорить об этом use() методе. Помните, что разработчик не должен создавать экземпляр класса Builder. Мы хотим, чтобы его конструктор был приватным, но нам также нужна точка входа.

Итак, пошаговая реализация класса Builder:

Объявите класс (да…), реализующий все необходимые вам интерфейсы. Существует частная переменная greetStr, это объект, который мы в конечном итоге хотим построить (с этого момента BR - Builder Result).

Создайте частный конструктор, который принимает начальное значение BR. Таким образом, мы не позволяем разработчику создавать экземпляр самого конструктора.

Мы создаем статическую функцию use(), которая служит точкой входа, и внутренне создаем объект Builder. Передайте начальное значение BR и верните приведенную версию построителя. Эту функцию также можно записать так:

но я нахожу первый способ менее подробным.

Двигаясь дальше, нам нужно реализовать ILanguage функций:

Мы просто мутируем BR (greetStr) по мере необходимости и возвращаем экземпляр сборщика (this), приведенный в качестве следующего шага (IGreet).

Переходим к реализации IGreet:

Это шаг, на котором у нас есть некоторая бизнес-логика. Как именно мы должны поступать с ошибками, зависит от варианта использования. Здесь я просто выбрасываю ошибку. Если все в порядке, измените BR по мере необходимости и верните экземпляр Builder в качестве следующего шага (IBuild).

Последний шаг. Просто верните внутренний объект BR. Вот полная копируемая реализация:

interface ILanguage {
    english: () => IGreet;
    spanish: () => IGreet;
}
interface IGreet {
    greet: (name: string) => IBuild;
}
interface IBuild {
    build: () => string;
}
class Builder implements ILanguage, IGreet, IBuild {
    
    private greetStr;
    private constructor(initVal: string) {
        this.greetStr = initVal;
    }
    
    static use(): ILanguage {
        return new Builder('');
    }
    
    english(): IGreet {
        this.greetStr += 'Hello, ';
        return this;
    }
    spanish(): IGreet {
        this.greetStr += 'Hola, ';
        return this;
    }
    
    greet(name: string): IBuild {
        if(!!name || name.length < 3)
            throw 'invalid parameter';
        this.greetStr += name;
        return this;
    }
    build(): string {
        return this.greetStr;
    }
}

Напутствие

Это была небольшая демонстрация. Освоившись с концепцией, вы можете попробовать разработать другую логику ветвления. Сборщики — хороший способ что-то делать, особенно если вы пишете библиотеку для использования другими разработчиками.

Несколько мелких замечаний и предупреждений:

1. TypeScript не поддерживает запечатанный класс (класс, который не может быть унаследован), и классы-строители должны быть запечатаны.

2. TypeScript также пока не поддерживает классы partial, поэтому все реализации этих методов для каждого шага забиты в один файл. Это может стать очень загроможденным. Попробуйте разделить разделы по комментариям, для собственного здравомыслия.

Надеюсь, что это было интересно. Спасибо за прочтение :)