Как правильно подходить к инициализации объекта (Factory, Init, DI), шаблона проектирования? - PullRequest
0 голосов
/ 01 мая 2020

Как лучше всего обрабатывать следующий случай: у нас есть класс, который внедряет какой-то другой класс в конструктор. Конструктор помимо этой инъекции имеет некоторые другие параметры.

class A
{
    constructor(B b, int x, int y);
}

Только из-за того, что конструктор имеет неинъекционные значения, которые каждый раз отличаются, мы не можем больше полагаться на IO C и обращаться с ними вручную.

Есть 2 способа: 1) Реализовать метод Init (int x, int y), который инициализирует наш объект с неинъекционными свойствами и удаляет их из конструктора, поэтому IO C framework будет обрабатывать его автоматически 2) Создайте фабрику, которая будет иметь метод создателя для этого объекта, и этот метод будет принимать x и y

1)

class A
{
    constructor(B b);
    init(int x, int y);
}

2)

class A
{
    constructor(B b, int x, int y);
}

class AFactory
{
   constructor(B b);
   createA(int x, int y)
   { return new A(b, x, y); }
}

Недостатки 1-го способа - нам нужно объявить все инициализируемые переменные как обнуляемые, потому что инициализация не гарантируется, и мы должны помнить, чтобы вызвать метод init.

Недостатки 2-го пути - если объект будет иметь много инъекции - нам нужно ввести их на заводской c -тор и передать их c -тору создаваемого объекта

Самый безопасный ИМО - это 2-й подход, как это безопаснее, чем 1-й с точки зрения гарантий инициализации, но он недостаточно хорош

Может быть, есть другой способ сделать это или улучшить способы, описанные выше?

Этот вопрос может быть связан в целом для всех языков и платформ, но, к вашему сведению, я использую обычную машинопись + инверсию

@ Update @Steven Вопросы о решениях: 1) передача данных времени выполнения через вызовы методов API 2) получение данных времени выполнения из указанных c абстракций, которые позволяют разрешать данные времени выполнения

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

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

Что бы вы порекомендовали в этом случае ?

Вот более подробный код:

Код клиента:

await this.switchToRunningState(context);

const authResult = await this.getAuthResult(context);

const executionResult = await this.execute(context, authResult);

await this.outputExecutionResult(context, executionResult);

Проблема заключается в результате аутентификации и выполнении. Итак, вот как я использую результат аутентификации:

executor
{
    c-tor(authResult, executionClient) -> app logic
    ... some methods
}

executionClient
{
    c-tor(authResult, httpClientFactory) -> encapsulated 3rd party API http calls
    ... some methods
}

httpClientFactory
{
    create(authResult) -> httpClient with auth data in cookies
}

Я придумал другое решение: создать некую абстракцию хранилища с помощью методов get и set. Метод set будет вызываться сразу после аутентификации, а метод get будет вызываться в конце этой цепочки - httpClientFactory для заполнения куки с таким результатом аутентификации. Но это тоже небезопасно. Мы должны помнить, что метод set должен вызываться, поэтому он тоже кажется ненадежным

Это описание случая, когда передача данных во время выполнения через метод будет неудобной, так как executeClient имеет много методов, связанных с взаимодействием API

Описание случая, когда при создании абстракций может появиться много классов:

public createIndefiniteProgressTracker(step?: number, initialWorkDone?: number): ProgressTracker<TProgressNotificationResponse> {
        return new IndefiniteProgressTracker(injected-deps..., step, initialWorkDone);
    }

    public createDefiniteProgressTracker(totalWork: number, step?: number, initialWorkDone?: number): ProgressTracker<TProgressNotificationResponse> {
        return new DefiniteProgressTracker(injected-deps..., totalWork, step, initialWorkDone);
    }

Этот случай также может быть решен путем передачи этих параметров в метод - track (... args): void Но мне кажется, что передача таких данных, как totalWork, step и initialWorkDone, необходима только один раз (c -тор или фабрика) и избыточна при каждом вызове метода

Обновление 2: у меня есть идея разобраться с аутентификацией некоторым образом:

abstract class AuthManager <- IAuthManager
c-tor(IAuthenticator authenticator)
public auth(){authResult = authenticator.auth(...); saveAuthResult(authResult)};
protected saveAuthResult(authResult);
MyAuthManager <- AuthManager
c-tor(IAuthResStorage storage);
protected saveAuthResult(authResult){storage.save(authResult)};

И позже я могу использовать IAuthResStorage для получения данных аутентификации

...