- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
struct ServiceProvider1
{
ServiceProvider1(Service2& service1, Service3& service2, Service3& service3, Service4& service4, Service5& service5):
service1(service1),
service2(service2),
service3(service3),
service4(service4),
service5(service5),
{}
fun<Service1> service1;//fun - функциональный объект (operator() перегружен), хранящий ссылку на сервис, чтобы не писать кроме членов ещё и две функции - константную и не константную.
fun<Service2> service2;
fun<Service3> service3;
fun<Service4> service4;
fun<Service5> service5;
};
class Service1
{
public:
template<class ServiceProvider>
Service1(ServiceProvider serviceProvider):
service2(serviceProvider.service2()),//Ссылки на сервисы получаем.
service3(serviceProvider.service3()),
myMember1(serviceProvider),//эти мемберы сами внутри воспользуются провайдерами зависимостей
myMember2(serviceProvider),
myMember3(),
myMember4(myServiceProviderGeter<ServiceProvider>()),//Этому мембору понадобились новые зависимости, часть тех, что хранятся в ServiceProvider, а часть новых среди членов Service1.
myMember5(myServiceProviderGeter<ServiceProvider>())
myMember6(myServiceProviderGeter<ServiceProvider>())
{}
...
private:
template<class BaseServiceProvider>
struct MyServiceProvider: BaseServiceProvider
{
MyServiceProvider(BaseServiceProvider baseServiceProvider, Service6& service6, Service7& service7):
BaseServiceProvider(baseServiceProvider),
service6(service6),
service7(service7)
{}
fun<Service6> service6;
fun<Service7> service7;
};
template<class BaseServiceProvider> MyServiceProvider<BaseServiceProvider> myServiceProviderGeter(BaseServiceProvider baseServiceProvider) const
{
return MyServiceProvider<BaseServiceProvider>(baseServiceProvider, this->myMember2, this->myMember3);
}
};
...
ServiceProvider1 sp(...);
Servive1 service1(sp);
Service8 service8(sp);
Service9 service9(sp);
...
+ wiring во время компиляции, забыть какие-то зависимости попросту невозможно
+ никаких виртуальных методов, ммаксимум перформанса
+ абсолютная развязка между модулями
- рукопашный wiring
- прощай, автокомплит, нам будет тебя не хватать.
- весь код в ашках, собираться будет часами (хотя геймдев оценит, ибо производительность)
Конкретные имена классов, как у последнего нуба ;)
> Чем тебе не нравится?
По большей части из-за "прощай, автокомплит, нам будет тебя не хватать".
Ну и если циклическую зависимость захочется - двойной облом из-за иньекции в конструктор и статического полиморфизма. Хотя циклические зависимости не нужны.
Иди на хуй, еболдыш!
Иди на хуй, еболдыш!
Иди на хуй, еболдыш!
Иди на хуй, еболдыш!
Между прочем этот код для списков типов идеален. Все типы полные и не являются базовой абсракцией, а чистая конкретика. Конкретнее некуда.
http://ideone.com/aEBSFM
Я всего лишь хотел показать, что даже если вдруг понадобится передать туда абстрактный класс (ну например мутим циклическую зависимость) то код не придется переписывать ;)
> Ты производительность теряешь.
Само собой.
> Не быть тебе гейдевщиком.
Печаль-беда...
Я рад что ты это понимаешь. Но ты же понимаешь, что не всё потеряно! Измени себя!
Так у него вся книга про policy-based programming, не?
Да как-то оно не устраняет зависимости, а наоборот усложняет код и создает новые... Конфигурация сервисов перемешана с самими классами.
Гетера мужского пола?
> Я вообще не понимаю о чем они
Какая-то кривожопая реализация dependency injection?
Наверное
Какой-то хренью занимаются. Синглтоны им не угодили.
будет гдето xml(или даже какойто config.h) где будет перечислен какие сервисы зависят от каких, и какие в какой последовательности создаются и их проперти
Ха! Геймдев потихоньку превращается в Ынтырпрайз.
правильно
>>Нормальный геймдев всегда Ынтерпрайз.
неправильно
Я так понимаю вы меня ненавидите)
http://static2.wikia.nocookie.net/__cb20110314162138/mlpfanart/images/0/05/Pinkie_Pie_haters_gonna_hate.gif
> Конфигурация сервисов перемешана с самими классами.
Это паттерн такой, Service Locator. От того такое название. К сервисам отношения не имеет. Только в данном случае паттерн несколько извращенный, но не суть. Предназначен для введения зависимостей в классы.
Да ну? Ты же не думаешь, что я говорю о виндовых службах? :)
Есть классы, предоставляющие некий сервис (логгер, ресурс манагер и т.п.), другие классы хотят их юзать и спрашивают ссылку на них у сервислокатора (в твоем случае почему-то названного service provider'ом). Так что вполне так имеет отношение к сервисам.
> несколько извращенный
Мягко сказано... Я не завидую тому, кто будет поддерживать подобный код. Тут же добавление нового класса, который от чего-то зависит и кому-то понадобится - +1 "сервиспровайдер". Поменять порядок инициализации - перепиливать пару сервиспровайдеров.
систему логирования, систему системных событий, ... надо ещё подумать что туда занести. Остальное можно передавать обычными параметрами.
Просто без нее можно запилить один универсальный локатор в духе locator.put(log); Logger &log = locator.get<Logger>(). При неправильном порядке просто кинет экцепшн при старте. На производительности особо не скажется, т.к. ты все эти поля один хрен выписываешь при старте, а не дергаешь из локатора каждый раз.
Теперь куча зависимостей спрятана в общий класс и в случае очень глубокой иерархии и куч объектов на разных уровнях (требующего примерно одинаковых зависимостей или меньше зависимостей) получает практически один параметр. В некоторых случаях будет меньше писанины. Ошибки типизации не переносятся на этап выполнения. Ошибки поиска зависимостей опять же не переносятся на этап исполнения. Интерфейсы можно не выделять, если это важно для приложения ради высокой производительности. То есть ради производительности не используются виртуальные функции, не используется поиск в иок контейнере, используются объекты на стеке или глобальные, используются самый конкретный потомок, а не какой-то его предок. В случае рефакторинга не придется заменять всюду по коду кучу зависимостей во всех параметрах, тк однажды упаковав новый в сервис провайдер сервис - он будет заменен на всех уровнях ниже по иерархии владения во всех экземплярах классов, куда передавали сервис провайдер.
В нашем проекте не используются виртуальные функции до того, как без них не обойтись. Не считаю это плюсом, но скорости говорят добавляет. Сейчас садиться и заводить для всего виртуальные интерфейсы уже не охота. Написано много. Ну и если сделать ServiceProvider виртуальным, тогда придется кастить, а это перенос всех ошибок на время выполнения. Хотелось бы избежать.
Я подумываю использовать виртуальные или не виртуальные сервиспровайдеры или иок контейнеры для разруливания зависимостей между объектами в крупной системе, а синглтоны отправить на помойку истории. Их реально много стало. Все что с ними - просто напрочь не тестируемо и не тестируется. Так что нужно избавляться, пока совсем не поздно. Вот думаю чем заменить.
Ну IoC же не заставляет тебя юзать интерфейсы и создавать объекты в куче. Ты же вполне можешь пихать и вытряхать из него конкретные классы, инстанциированные на стеке main'а. На задержку тут всем похрен, ибо это всего лишь инициализация, а не горячий цикл.
> Ошибки типизации не переносятся на этап выполнения.
С IoC тоже не переносятся. Там только ошибки поиска зависимостей, но они опять же отловятся на первом запуске, т.к. вся конфигурация IoC'а у тебя забита в статику.
А я от этих проблем избавился почти.
Ну и использовать для идентификации типа сам тип никак нельзя. Только если тип-спутник. Тк часто нужно для одного типа много экземпляров. У вас получился локатор синглтонов. У меня их конечно много, но не все же. Ну и от синголтонной болезни вообще хочется избавиться.
Так точно ;) Тут согласен, надо что-то более специфичное, чем айдишку класса.
> Ну допустим я захочу выпереть Bar и заменить на Foobar в половине экземпляров классов?
Так на той реализации один хрен это не выйдет... Классы же не шаблонные, а зависимости у них не абстрактные. Точно так же придется перепиливать кучу кода, заменяя Bar на Foobar во всех классах, которые захотят его юзать.
Может быть ты имел в виду раздачу разных инстансов одного класса разным классам? Вот тут да, с моей реализацией жопа, т.к. она по сути коробка с сигнлтонами.
http://ideone.com/Dc735Q
Я бы хотел такой IOCC:
1)Что бы сам разруливал зависимости и управлял созданием объектов в правильном порядке, передавая нужное число влияющих параметров (сервисов) в конструктор или иногда в сеттер (хотя последнего у нас вроде пока нет, но обязательно появится с переносом кода из другой ветки).
2)Можно регать часть сервисов (как bormand::locator->put), тк сразу перевести все на иокк не получится.
3)Нужен механизм зависимости от событий. То есть чтобы по мере создания объектов дергались некоторые зарегистрированные функции. У нас нет возможности все зависимости описать объектно. Есть конечно, но это будет очень накладно, тк реально в конструктор эту зависимость придется передать, а по факту её объектной формой пользоваться не придется. Через событийные зависимости думаю описывать и вариант с сеттером, тк у него может быть нестандартное название.
4)Не плохо бы по максимуму сохранить ошибки компиляции и автоматизацию. Поэтому пусть вместо традиционных строк будут типы-спутники экземпляра класса. Это позволит передавать не T в get, а T_descriptor условно говоря. И тогда возвращаемое значение get может само вычисляться. Ну и неплохо бы дать указывать возвращаемое значение get, чтобы поддержать типы с наследованием.
5)Описание в XML не мешает конечно, но не нужно. Не плохо бы описание в EDSL. Какой едсл стиль для этого выбрать, если самому придется писать?
Что-то подобное есть на примете из готового? Систем с зависимостью от событий не видел. А тут это корневой момент, избавится от них нельзя.
Я джва года хочу такой контейнер.
> Что-то подобное есть на примете из готового?
Х.б.з., я крестовые IoC вообще не раскуривал.
Судя по тому, что они не особо развиваются - не особо это и реально.
А как тогда вы с зависимостями боретесь?
> Судя по тому, что они не особо развиваются
Я штук десять нашел сходу. Документацию ну наверное по 3-4ом. Те что без смотреть не стал.
> Я джва года хочу такой контейнер.
Тут это значит что не хотите? Тогда почему?
Синглтон с закатом солнца вручную (SomeShit::initialize(42, "100500")). Или рукопашная передача.
> Я штук десять нашел сходу.
Да, их полно, но что-то процент дохлятины, которую 5 лет не трогали, среди них очень велик.
> Тут это значит что не хотите?
Не, это просто прикол был, цитата из "корованов".
Идеи с EDSL для описания зависимостей есть?
Про зависимость от событий не совсем понятно. Некие коллбеки, вызываемые до и после создания некоторых инстансов?
> передавая нужное число влияющих параметров (сервисов) в конструктор
В крестах это хрен запилишь без бойлерплейта или кодогенерации - рефлексии же нет.
> Идеи с EDSL для описания зависимостей есть?
Тут надо подумать.
Пока только вот такой "EDSL" в голову приходит:
http://ideone.com/LWH6ye Иньекцию через сеттер можно делать сразу перед return'ом. Механизм событий о загрузке - сама фабрика. Регать готовые сервисы даже сейчас можно - просто зарегать фабрику, возвращающую готовый сервис. Порядок инициализации - определяет сам по зависимостям.
Естественно это всего лишь концепт, и пока работает только в режиме синглтона. Ну и в данном коде нету многих важных проверок и не решена проблема управления памятью...
- no_cache - контейнер тупо возвращает то, что вернула фабрика, и вызывает ее каждый раз
- cache - аля обычный синглтон
- tls_cache - thread-local синглтон А в метод add_factory можно передать режим кеширования:
Если бы я съехал - тут бы уже была ссылка на гитхаб с just another c++ IoCC.
> по человечески и понятно писать код
Окай, спущусь с небес на землю: Но это же скучно :)
Вижуалстудия? Текст ошибки кинь.
Текст большоооой
Блеать, я запостил и не посмотрел, что с++11 не включил. Спасибо!
http://ideone.com/UIra6C
Это жалкая пародия на IoC контейнер.
Ты описываешь контейнеру зависимости между классами (в данном случае через container::add_factory()), а затем можешь просить его запиливать инстансы этих классов. Все необходимые зависимости автоматически создадутся и инжектнутся ему через конструктор или свойства.
Я ninject юзал под .net, в курсе что - кого.
Как это меня жизнь скрутила, коль я для расслабона IoC на плюсах смотрю
Нет, постоянная. Это ж кресты. Рефлексии нету. Либо кодогенерация, либо адское шаблоноебство (и не факт, что получится), либо вот так вот перечислять все зависимости в том порядке, как они идут в конструкторе. Если в конструкторе кто-то поменяет порядок - компилятор сматерится, а ты просто переставишь их местами.
> всовываеim 2 раза тип
Первый - тег, второй реальный тип. Тег нужен чтобы например 2 разных лога зарегать, и отдать половине классов первый, а половине - второй.
> это бетка
Да какая это бетка, это так, набросок для иллюстрации идеи, даже на пруф оф концепт не тянет.
печально, но в принципе не суть - все равно в бинд в одном месте будет производится
>>
а почему тогда
c.add_factory<abstract_logger, abstract_logger>
а не
c.add_factory<abstract_logger, file_logger>
или не
c.add_factory<abstract_logger>
(на счет последнего не уверен, но там вреде как по умолчанию стоит 2 параметр=первому)
?
Идея примерно такая - допустим нам надо часть инфы отправить в особый лог (глупый пример, но пох), тогда мы делаем так: И гейму попадет отладочный лог, а менеджеру ресурсов - обычный. По идее второй параметр надо бы заныкать в первый, в духе struct debug_logger { typedef abstract_logger type; } и передавать только один параметр, но лень...
Я просто наоборот привык)
Ninject.Bind<IWeapon>().To<Sword>();
Да почему, так как ты написал, так и есть.
Сначала тег и интерфейс (но можно и конкретный класс, для совместимости со старым кодом). Затем фабрика, возвращающая конкретный класс: Просто есть еще дополнительная возможность - два инстанса одного класса можно засунуть, пометив их разными тегами.
Ну то есть что возвращает - то и привязано)
сижу, освежаю паттерны в голове. наткнулсяна декаратор - не могу понять что за хрень. тупил минут 10 глядя на схему. А потом такой - аааа, так этож бездна анального делигирования.
мораль сей басни такова - пишите статью - приводите нормальные примеры как я)
Не увидел EDSL.
А зачем с ними бороться?
Пусть жависты борются с ними мегабайтами xmlя, фабриками фабрик, синглтонами и декораторами.
Я серъезно. В каких частоиспользуемых популярных программах сделано это ваше IoC.
> А зачем с ними бороться?
Не имеет смысла бороться с зависимостями. Зависимости - это часть тебя. Я вот курю.
IoC - не серебряная пуля. Но она существенно помогает поддерживать проект. Все становиться модульным и заменяемым. Ня!
Только вот на практике никто никогда ничего не заменяет :) Потому что работает - не трогай.
Лучше бы тестирование в качестве примера привел, для него пользы от IoC побольше.
Но так как мокинг на интерфейсах строится, то и ioc весьма кстати)
Вот, учитесь. Слова понявшего жизнь кодера. +100500
90% оверинжинирнга в программировании от того что пытаются писать слишком модульный, слишком расширяемый и слишком заменяемый код.
Браузер, торрент-клиент, кодеки, среда разработки, контроль версий, компилер, виртуальная машина - да ни одна из них.
И весь этот софт гораздо сложнее того что пишем мы.
Ладно какие известные софтины/либы самой жабы написаны с использованием IoC? На ум приходит только мавен.
ну и пусть. фанатикам всегда нужна религия. тебя это чем-то задевает? юзаю синглтоны, доволен как рак
Я говорю о том, что так писать выгодно с точки зрения разработки, а само написание не требует усилий. Примеры не могу привести, разве только что из личного опыта написания лаб)
Я вообще 99% лаб делал консольными, чтобы не засорять их лишним кодом.
Лабы выгодно сдавать, уверяю.
>>дописал либу - добавил кнопку
А нужен ли нам для этого IoC? Не надо путать контрактное программирование и DI.
Во всех других языках программы каким-то образом успешно работают и без этого порождения Фаулера.
Повторюсь:
>>>Не надо путать контрактное программирование и DI.
>Не надо путать контрактное программирование и DI.
Я бы сказал, не надо путать loC и DI. Первое как раз заключается в том, что классы зависят только от интерфейсов. Второе подразумевает внедрение реализаций с помощью middleware - IoC-container. Так что в этом вопросе я скорее на стороне кегдана.
По работе всегда приходилось использовать spring. В личных проектах предпочитаю Guice, он весьма приятен в обращении.
В крестах не использую.
А как же там борешься с зависимостями?
Явная инициализация всего, что нужно, в main.
Ну да. Да и типичные крестопроекты обычно не плодят столько абстракций, там вайринга не так много.
Опять же, на текущем месте работы принято разрабатывать небольшие, специализированные сервисы и интегрироваться через xml-rpc/json-rpc. Так проще обеспечить отказоустойчивость, репликацию и балансировку нагрузки. Или поменять язык реализации при необходимости.
Я практически не слышал чтобы проекты (даже громадные) на сишке, крестах использовали какие-либо фреймворки для вайринга. Равно как не слышал что кто-то сильно от этого страдал и жаловался.
Так вот я и думаю может все эти iocc - жабизм головного мозга. Создаём себе кучу проблемабстракций, а потом пытаемся с ними как-то управиться.
PS А создатель спринга кстати уже ушёл в контору к Одерски.
А я для всяких логов, конфигов и прочей хрени, которая 100% одна на проект предпочитаю синглтоны с ручной инициализацией через class_name::initialize().
- можно забыть инициализнуть (что отловится по ассерту на первом же отладочном пуске)
+ не надо заморачиваться с передачей (иньекции без контейнера - для мазохистов)
+ шустро и на 146% потокобезопасно (что в ленивых синглтонах достигается медитацией и плясками, если вообще достигается)
+ киллер фича: можно передать аргументы
Кстати да. От ленивых синглтонов профита обычно мало, а вот гемора - много.
Мы слишком ленивы чтоб писать истинно ленивые синглтоны!
Ололо, жаба и нетфреймворка -батхерт. ВКрестах проблем нет, брат жив.
Ок, теперь передай ленивому синглтону аргументы.
> ВКрестах проблем нет
Нет тредов - нет проблем.
P.S. А какой из способов юзал брат, который жив?
Вы не любите меня, я не люблю вас, но завтра у меня в 9 утра по Москве собеседование на должность программиста .NET
Материте меня, сволочи
Problems? %)
И хде он взял arg1, arg2, arg3? %)
P.S. И ты же сам вроде бы писал, что этот синглтон мейерса непотокобезопасен в некоторых компиляторах...
Насколько я понимаю речь с самого начала треда идет именно об инжекциях имплементаций и IoC-контейнерах. А не :
>>том, что классы зависят только от интерфейсов
Если вырвать мои слова из контекста треда, то да.
Контрактное программирование - это вообще не то
IoC - ослабление зависимости через интерфейс - так?
Так. Но я предпочитаю терминологию:
"ослабление зависимости через интерфейс"=="контрактное программирование"
IoC в смысле IoC-контейнер (да я забываю лишнюю С), который сам начиняет другие объекты.
То бишь делает wiring, о котором борманд написал изначально comment214212
это даже близко не то- контрактное программирование
ioC и ioCC - вещи разные) iocc я не юзал - это сильно гибко, мне так не нужно было)
А если нужны - то само собой неправильно.
Типа такого:
Ну все выше сказанное - мое имхо, и может быть оспорено.
Но тред-то не про это...
Добывать интерфейсы всяких служб. Например:
Во-вторых, не пойму, чем это лучше, чем
И в-третьих, согласись, что даже в текущем виде кода прокидывать этот context, везде и всюду - плохая идея.
Хотя, есть еще более плохое решение - хранение подобного контекста в сингтоне.
А контекст... каждая активити (экранная форма) реализует контекст, каждый сервис, емнип, тоже. Поэтому с его добычей особых проблем нет.
Правда в моем случае нам не придется даункастить лишний раз, а это потенциальное место для ошибки.
А то, что этот контест есть везде, как раз и есть та проблема, потому, что если ты захочешь, понять, что там РЕАЛЬНО нужно, или захочешь замокать все реальные дипенденсы, для теста, все, попа.
Ну это как мне кажется.
Но все равно, согласись, постоянно доставать все из контекста - плохая идея.
А другим классам никто не заставляет передавать контекст целиком, там уже ты сам за все в ответе.
Это Интернет Эксплорер не нужен.