Re[19]: Конструктор с параметрами vs метод Init -- стоит ли
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 08.04.16 09:35
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Проблема в том что конструктор не описывается интерфейсами


Зато интерфейсом или делегатом описывается фабрика.

S>А то что нужно единожды вызвать Init после отказа от концепции конструкторов с параметрами -- это правило можно применять для всего проекта и описать/запомнить 1 раз.


Контролировать вот только не получится.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
AVK Blog
Re[21]: Конструктор с параметрами vs метод Init -- стоит ли
От: Berill Азербайджан  
Дата: 08.04.16 10:46
Оценка:
Здравствуйте, Shmj, Вы писали:

B>>С другой стороны, имхо, стоит задуматься над следующим. Если каждый раз когда вам требуется объект сервиса, вы проделываете unityContainer.Resolve, то принципиально это ничем не отличается от вызова фабричного метода.


S>Разница в том что в unityContainer я регистрирую множество сервисов. Вы предлагаете передавать в конструктор сервиса по 5-6 фабричных методов? Чем это лучше?


B>>В свою очередь, это намекает на то, что вы, скорее всего, протаскиваете свой объект юнити-контейнера туда, где вы его используете. Лично у меня складывается такое впечатление. И тут встает закономерный вопрос, а нужен ли этот юнити вообще?!


S>В моем случае реальные сервисы отрабатывают достаточно долго, по этому для целей тестирования логики используются фейковые сервисы, возвращающие набор фейковых данных. Как вы предлагаете это реализовать? Передавать к конструктор одного сервиса по 5-6 фабрик на другие сервисы, которые он использует для своей работы?


Параметритизированный фабричный метод вам не подходит для этого?

B>>Если посмотреть на код метода Init (который вы приводите), то опять же, он вам не гарантирует корректность переданных настроек. Если вам еще и это надо проверять, то спросите себя: а должен ли ваш объект сервиса этим заниматься?!


S>Init показывает какие обазательные данные необходимы для инициализации сервиса.


Параметр в конструкторе делает абсолютно тоже самое. И правильнее всего это делать именно в конструкторе, т.к. это зависимость. Init можно и забыть вызвать, а вот конструктор не получится забыть. Если вы один все разрабатываете, то вы может и не забудете. А если у вас команда, то вы и не проконтролируете все и везде.

B>>Если у вас задача: создать объект сервиса с корректными настройками — то я бы разделил это на 2 подзадачи:

B>>1. Проверка корректности настроек

S>Про проверку корректности вопроса не было. Вопрос в том что в интерфейсе нельзя описать параметры конструктора.



B>>2. Передача корректных настроек сервису либо при его создании (если эти же настройки используются не только для одного метода), либо в сам метод, где эти настройки используются


S>Настройки используются для всех методов. Можно, конечно, в каждый метод их передавать в качестве первого параметра, но не хотелось бы замусоливать, ведь достаточно один раз передать в конструктор или в метод Init.


В этом случае настройки — обязательная зависимость. Это еще один аргумент в пользу того, чтобы передавать эту зависимость через конструктор. Но вы тут опять упретесь, что нельзя описать конструктор в интерфейсе (а надо ли?!). Что, по вашему мнению, приводит к сложностям использования юнити-контейнера. Хотя для нормального DI(IoC)-контейнера это не представляет никакой сложности. А для юнити это есть и подавно.
тут автор показывает как это делается в версии 2.0
Dependency Injection with Unity

Разве ваша проблема не решается? Что вам еще нужно?
Re[20]: Конструктор с параметрами vs метод Init -- стоит ли
От: Shmj Ниоткуда  
Дата: 08.04.16 13:18
Оценка:
Здравствуйте, AndrewVK, Вы писали:

S>>Проблема в том что конструктор не описывается интерфейсами

AVK>Зато интерфейсом или делегатом описывается фабрика.

Верно, но это еще одна дополнительная абстракция. Получается для каждого сервиса с параметром должна быть фабрика. И все равно нужно помнить что сервисы создаются посредством фабрики (как и в случае с Init нужно помнить что требуется ее вызов).

S>>А то что нужно единожды вызвать Init после отказа от концепции конструкторов с параметрами -- это правило можно применять для всего проекта и описать/запомнить 1 раз.


AVK>Контролировать вот только не получится.


А с фабрикой вы сможете контролировать только время жизни самой фабрики.
Re[19]: Конструктор с параметрами vs метод Init -- стоит ли и
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 08.04.16 13:21
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Все зависимости должны быть в одном месте. Если я хочу вместо реального сервиса, который работает длительное время, подставить фейковый (для целей тестирования) -- то вы предлагаете по всему коду проекта зависимости искать? Сейчас все в одном файле и быстро можно переконфигурировать для тестов. Причем одновременно может существовать несколько конфигураций (одна тестовая, другая реальная).

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

S>К конкретной реализации фабрики не привязано. Добавил интерфейс абстрактной фабрики, котоарая имеет 2 реализации: тестовую и реальную. Тестовая используется для целей тестирования/отладки. Выбор какую использовать задается в конфигурации.

Ну а если какой-нить "оптимизатор" через полгода решил "оптимизировать" фабрику, и всегда отдавать один и тот же закешированный экземпляр сервиса? Упс. Я вообще стараюсь все сервисы делать stateless, то есть в твоём случае я бы обернул инициализацию и использование сервиса внутрь другого сервиса. В этом случае он станет stateless, и вероятность граблей в дальнейшем уменьшится на много порядков.
[КУ] оккупировала армия.
Re[22]: Конструктор с параметрами vs метод Init -- стоит ли
От: Shmj Ниоткуда  
Дата: 08.04.16 13:24
Оценка:
Здравствуйте, Berill, Вы писали:

B>Параметритизированный фабричный метод вам не подходит для этого?


Это дополнительная абстрация -- по сути ничем не отличается от Init.

B>Параметр в конструкторе делает абсолютно тоже самое. И правильнее всего это делать именно в конструкторе, т.к. это зависимость. Init можно и забыть вызвать, а вот конструктор не получится забыть. Если вы один все разрабатываете, то вы может и не забудете. А если у вас команда, то вы и не проконтролируете все и везде.


Когда вы создаете объект посредством IoC-фреймворка, то передача параметров в конструктор происходит в виде нетипизированного массива ResolverOverride. Т.е. там нет абсолютно никакой информации о типе и количестве параметров. По этому можно и забыть передать, как и забыть вызвать метод Init. Во время исполнения и та и другая ошибка обнаруживаются примерно одинаково.
B>В этом случае настройки — обязательная зависимость. Это еще один аргумент в пользу того, чтобы передавать эту зависимость через конструктор. Но вы тут опять упретесь, что нельзя описать конструктор в интерфейсе (а надо ли?!). Что, по вашему мнению, приводит к сложностям использования юнити-контейнера. Хотя для нормального DI(IoC)-контейнера это не представляет никакой сложности. А для юнити это есть и подавно.
B>тут автор показывает как это делается в версии 2.0
B>Dependency Injection with Unity

B>Разве ваша проблема не решается? Что вам еще нужно?


Unity для этих случаев использует передачу параметров при Resolve в виде массива ResolverOverride. Никаких данных о типе и количестве параметров использующий видеть не будет.

Остается либо Init либо воздание дополнительной абстракции в виде фабрики. Ну или в каждый метод передавать настройки отдельно.
Re[21]: Конструктор с параметрами vs метод Init -- стоит ли
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 08.04.16 13:53
Оценка:
Здравствуйте, Shmj, Вы писали:

S>>>Проблема в том что конструктор не описывается интерфейсами

AVK>>Зато интерфейсом или делегатом описывается фабрика.
S>Верно, но это еще одна дополнительная абстракция.

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

S> Получается для каждого сервиса с параметром должна быть фабрика.


Не для каждого, а только для того, для которого нужен контракт на создание экземпляра.

S> И все равно нужно помнить что сервисы создаются посредством фабрики


Помнить не нужно. Делаешь реализацию приватной и кроме как через фабрику ее экземпляр не создашь.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
AVK Blog
Re[22]: Конструктор с параметрами vs метод Init -- стоит ли
От: Shmj Ниоткуда  
Дата: 08.04.16 14:27
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Помнить не нужно. Делаешь реализацию приватной и кроме как через фабрику ее экземпляр не создашь.


Но мы же доверили создание экземпляров Unity.

У меня из проекта видны только интерфейсы (контракты). С какими конкретно реализациями работаете -- нет информации. Вызвать конструктор сервиса не возможно напрямую, т.к. реализации не видны.

По этому вы можете сделать Resolve<IMyService>, вместо Resolve<IMyServiceFactory>.CreateMyService(settings);
Re[23]: Конструктор с параметрами vs метод Init -- стоит ли
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 08.04.16 15:09
Оценка:
Здравствуйте, Shmj, Вы писали:

AVK>>Помнить не нужно. Делаешь реализацию приватной и кроме как через фабрику ее экземпляр не создашь.

S>Но мы же доверили создание экземпляров Unity.

Не мы, а вы.

S>У меня из проекта видны только интерфейсы (контракты). С какими конкретно реализациями работаете -- нет информации. Вызвать конструктор сервиса не возможно напрямую, т.к. реализации не видны.


И это логично. Хотя бы потому что у разных реализаций сервиса могут быть разные параметры конструкторов.

S>По этому вы можете сделать Resolve<IMyService>, вместо Resolve<IMyServiceFactory>.CreateMyService(settings);


Как не ресолвить фабрики в юнити тебе ссылку уже дали.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
AVK Blog
Re[24]: Конструктор с параметрами vs метод Init -- стоит ли
От: Shmj Ниоткуда  
Дата: 08.04.16 15:40
Оценка:
Здравствуйте, AndrewVK, Вы писали:

S>>По этому вы можете сделать Resolve<IMyService>, вместо Resolve<IMyServiceFactory>.CreateMyService(settings);

AVK>Как не ресолвить фабрики в юнити тебе ссылку уже дали.

Вы имеете в виду передавать в Resolve параметры в нетипизированном массиве ResolverOverride Или я что-то пропустил?
Re[23]: Конструктор с параметрами vs метод Init -- стоит ли
От: Strategy  
Дата: 09.04.16 08:38
Оценка: 6 (1)
S>По этому вы можете сделать Resolve<IMyService>, вместо Resolve<IMyServiceFactory>.CreateMyService(settings);

Пользователь службы не будет использовать ни Resolve<IMyService>, ни Resolve<IMyServiceFactory>.CreateMyService(settings) для получения экземпляра службы.

Вместо этого класс, которому требуется служба для выполнения своих функций, запросит в конструкторе

либо службу IMyService

class ServiceUser {

    public ServiceUser(IMyService MyService) {

        var File = MyService.Download(URL);
    }
}


либо фабрику службы IMyServceFactory, если хочет создавать много служб с разными настройками

class ServiceUser {

    public ServiceUser(IMyServiceFactory MyServiceFactory) {
    
        var MyService = MyServiceFactory.CreateMyService(Settings);

        var File = MyService.Download(URL);
     }
}


либо лямбда-функцию Func<Settings, IMyService>, если не хочет расписывать отдельный фабричный интерфейс

class ServiceUser {

    public ServiceUser(Func<Settings, IMyService> MyServiceFactory) {
    
        var MyService = MyServiceFactory(Settings);

        var File = MyService.Download(URL);
    }
}


И обязанность контейнера / загрузчика предоставить всё это именно в том виде, в котором запросит пользователь через конструктор.

Можешь считать фабрику IMyServiceFactory и Func<Settings, IMyService> тем самым "интерфейсом, который описывает конструктор с нужным набором параметров и заменяет Init".
Re[24]: Конструктор с параметрами vs метод Init -- стоит ли
От: Shmj Ниоткуда  
Дата: 09.04.16 22:17
Оценка:
Здравствуйте, Strategy, Вы писали:

S>Пользователь службы не будет использовать ни Resolve<IMyService>, ни Resolve<IMyServiceFactory>.CreateMyService(settings) для получения экземпляра службы.


S>Вместо этого класс, которому требуется служба для выполнения своих функций, запросит в конструкторе


Уже писали -- это удобно когда сервис вызывает внутри себя 1-2 других сервиса. Если же их больше -- то замусоливать конструктор 5-7 параметрами сервисов, которые внутри себя вызывают другие сервисы -- не подходит.

Ваш пример можно показать студентам в качестве идеального примера и все будут хлопать, так как выглядит красиво. Но в жизни все несколько сложнее, по этому Resolve нужно вызывать явно внутри сервиса.
Re: Конструктор с параметрами vs метод Init -- стоит ли использо
От: bazis1 Канада  
Дата: 10.04.16 03:46
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Собственно, вся прелесть конструктора -- вы можете быть уверенным, что если создан инстанс то определенное поле 100% имеет установленное значение (если установлено в конструкторе).

Конструктор, как и многие другие языковые средства, решает одну единственную задачу. Он позволяет средствами языка описать, что делать можно, а что нельзя. Т.е. вместо неявного "надо вызвать init(), а то будет падать" есть совершенно явное "инстанс можно получить, только вызвав конструктор с параметрами". И не надо искать в документации, как называется метод init, можно ли его вызывать повторно, и какие из методов работают без него. Язык Вам просто не даст ничего сделать без вызова соответствующего конструктора.

S>Зато конструктор имеет много минусов. К примеру, Generics не поддерживают создание инстанса если конструктор с параметрами. Так же для XML-сериализации требуется наличие конструктора без параметров, а значит у вас уже не будет той гарантии, ради которой конструкторы вообще задумывались.

Откройте для себя ObsoleteAttribute с параметром error=true

S>Еще минус, вы не можете добавить новый конструктор в класс с помощью Extensions-методов. Зато можно добавить новый метод Init.

S>И наверное самая большая проблема -- конструктор нельзя описать с помощью контрактов (interface).
Откройте для себя паттерн object factory.

S>Прихожу к пониманию что конструктор с параметрами не гибок и имеет больше минусов, чем плюсов. И лучшее решение всегда создавать конструктор без параметров + метод Init, если нужны параметры для инициализации класса. Если повторная инициализация запрещена -- это легко решается с помощью булевого поля _isInitialized.

S>Согласны?
Согласен, что на основе выборки частных случаев выводить глобальное правило и безусловно ему потом следовать — не очень умная стратегия. Есть случаи, когда конструктор удобней (с тем же readonly), есть случаи, когда init() будет лучше (скажем, хочется дергать event-ы из процедуры инициализации и по каким-то причинам нельзя объединить их в интерфейс). Для простых вещей вообще можно return new Object{Field1=xxx,FieldB=yyy}; делать и не жужжать.
Re: Конструктор с параметрами vs метод Init -- стоит ли использо
От: barn_czn  
Дата: 04.05.16 09:13
Оценка: +1
S>Согласны?

Нет. Универсальных решений нет. Я всегда за конструктор, если он возможен. И за readonly поля.
С конструктором есть еще одна проблема — async/await. Внутри конструктора нельзя сделать await.
Но даже эту проблему можно обойти:


public class MyClass
{
private MyClass()
{
}

private async Task Init()
{
    //await Any();
}

public static async Task<MyClass> New()
{
    var res = new MyClass();
    await res.Init();
    return res;
}

}


— вот и все! ваш Init() закрыт и никто не вызовет его 2жды.
Так что подумайте 10раз делая public Init.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.