SlideShare a Scribd company logo
DI в C++ тонкости и
нюансы
а так же IoC контейнеры на примере
Hypodermic
Щербаков Антон
компания СИГНАТЕК
Обо мне:
- решения в области СОРМ и
телекоммуникаций
- 24x7 сервисы с минимум GUI
- непрерывное усиление и развитие
команды
О презентации:
- личный опыт использования DI и IoC
- примеры тестов на GMOCK и GTEST
- … и c++ :)
Специфика работы
- Много долгоживущих проектов
- Которые нужно дорабатывать
- Дорабатывать быстро и качественно
С чего все начиналось...
Выводы:
Код должен быть тестируем
Код должен быть тестируем просто
Тестовое окружение должно быть
максимально простым
Что же такое DI?
...Кто слышал?
Dependency Injection
это design pattern
● Dependency это объект, который
используется (Service)
● Injection - передача зависимости,
зависящему классу (Client-у). При этом
Dependency становится состоянием
класса.
Пример с кофеваркой
/* Без внедрения зависимостей */
class CoffeMaker {
public:
CoffeMaker() {
m_heater = new Heater();
m_pump = new Pump();
}
Coffe MakeCoffe() { /* ... */ }
private:
Heater* m_heater;
Pump* m_pump;
};
int main() {
CoffeMaker* coffeMaker = new CoffeMaker();
coffeMaker->MakeCoffe();
}
/* Ручное внедрение зависимостей */
class CoffeMaker {
public:
CoffeMaker( Heater* heater, Pump* pump ) {
m_heater = heater;
m_pump = pump;
}
Coffe MakeCoffe() { /* ... */ }
private:
Heater* m_heater;
Pump* m_pump;
};
int main() {
Heater* heater = new Heater();
Pump* pump = new Pump();
CoffeMaker* coffeMaker = new CoffeMaker( heater,
pump );
coffeMaker->MakeCoffe();
}
class Heater : public IHeater {
public:
virtual void Heat() = 0;
};
class Pump : public IPump {
public:
virtual void Drip() = 0;
};
class CoffeMaker {
public:
CoffeMaker( IHeater* heater, IPump* pump ) {
m_heater = heater;
m_pump = pump;
}
Coffe MakeCoffe() { /* ... */ }
private:
IHeater* m_heater;
IPump* m_pump;
};
int main() {
// Пользователь класса определяет что именно
передавать
IHeater* heater = new Heater();
IPump* pump = new Pump();
CoffeMaker* coffeMaker = new CoffeMaker( heater,
pump );
coffeMaker->MakeCoffe();
}
Что получаем?
Кого инстанциировать решает пользователь
(MOCK, STUB)
Получаем слабою связность
Класс стал проще тестироваться
class Mock_IHeater : public IHeater {
public:
MOCK_METHOD0( Heat, void() );
};
class Mock_IPump : public IPump {
public:
MOCK_METHOD0( Drip, void() );
};
TEST_F( CoffeMakerTest, Should_heat_water ) {
Mock_IHeater heater;
Mock_IPump pump;
CoffeMaker coffeMaker( &heater, &pump );
EXPECT_CALL( pump, Drip() )
.Times( 1 );
EXPECT_CALL( heater, Heat() )
.Times( 1 );
coffeMaker.MakeCoffe();
}
Минусы?
Избыточный дизайн (чем как правило нужно)
“Архитектурный” шум в виде интерфейсов
НО тестируемость важнее!
Зависимость через указатель
Как контролировать потерю объекта?
А при многопоточности?
Кто отвечает за время жизни зависимости?
Чистые указатели - это уже дурной тон
Какие альтернативы?
std/boost:
shared_ptr
unique_ptr
weak_ptr
unique_ptr
Только класс клиент владеет и отвечает за
время жизни зависимоости.
Но тестировать не получится поэтому
unique_ptr
shared_ptr
Класс клиент так же отвечает за время
жизни
Или ответственность передана полностью
Потокобезопасен
НО есть проблема с циклическими связями
weak_ptr
За время жизни класс не отвечает и готов к
тому, что ее могут отнять
В качестве способа передачи
зависимости остались:
shared_ptr
weak_ptr
Внедряем зависимости:
Конструктор
как правило shared_ptr
Set-тер
как правило weak_ptr
class CoffeMaker {
public:
CoffeMaker( std::shared_ptr< IHeater > heater, std::shared_ptr< IPump > pump ) {
m_heater = heater;
m_pump = pump;
}
void SetBell( std::weak_ptr< IBell > bell ) {
m_bell = bell;
}
Coffe MakeCoffe() {
/* ... */
}
private:
std::shared_ptr< IHeater > m_heater; // Класс не может делать кофе без насоса и нагревателя
std::shared_ptr< IPump > m_pump;
std::weak_ptr< IBell > m_bell; // Класс может делать кофе и без колокольчика
};
Внедряем зависимости с weak_ptr
При DI лучше обходиться без
weak_ptr
Циклические связи - плохой “запах” в
архитектуре и дизайне
class CoffeMaker {
public:
CoffeMaker( std::shared_ptr< IHeater > heater, std::shared_ptr< IPump > pump ) {
m_heater = heater;
m_pump = pump;
}
/* ... */
private:
std::shared_ptr< IHeater > m_heater;
std::shared_ptr< IPump > m_pump;
};
TEST_F( CoffeMakerTest, Should_heat_water ) {
std::shared_ptr< IHeater > heater = std::make_shared< Mock_IHeater >();
std::shared_ptr< IPump > pump = std::make_shared< Mock_IPump >();
CoffeMaker coffeMaker( heater, pump );
EXPECT_CALL( *pump, Drip() )
.Times( 1 );
EXPECT_CALL( *heater, Heat() )
.Times( 1 );
coffeMaker.MakeCoffe();
}
Все хорошо… НО
Кто все это будет конструировать?
А внедрять зависимости?
И как это проверять?
Пример ручного связывания
{
auto transportLayer = std::make_shared< TcpTransportSystem >();
auto sormController = std::make_shared< SormControllerComponent >( sormType, acceptTimeOut );
auto sormMsgProcessor = std::make_shared< SormMsgProcessor >();
auto sormTransport = std::make_shared< TcpTransport >( transportLayer sormIp, sormPort, sormMessageProcessor );
auto sormComponent = std::make_shared< SormComponent >( sormType, sormController, sormTransport );
auto puTranspoort = std::make_shared< TcpTransport >( puIp, puPort, sormMessageProcessor );
auto puComponent = std::make_shared< PuModule >( puTransport );
auto operationScheduler = std::make_shared< RealTimeOperationScheduler >();
auto ioController = std::make_shared< IoController >( operationScheduler );
auto app = std::make_shared< DelveryService >( sormComponent, puComponent, transportLayer, ioController );
app.Start();
app.Release();
}
Composition root и Register Resolve
Release
{
// Register
auto transportLayer = std::make_shared< TcpTransportSystem >();
auto sormController = std::make_shared< SormControllerComponent >( sormType, acceptTimeOut );
auto sormMsgProcessor = std::make_shared< SormMsgProcessor >();
auto sormTransport = std::make_shared< TcpTransport >( transportLayer sormIp, sormPort, sormMessageProcessor );
auto sormComponent = std::make_shared< SormComponent >( sormType, sormController, sormTransport );
auto puTranspoort = std::make_shared< TcpTransport >( puIp, puPort, sormMessageProcessor );
auto puComponent = std::make_shared< PuModule >( puTransport );
auto operationScheduler = std::make_shared< RealTimeOperationScheduler >();
auto ioController = std::make_shared< IoController >( operationScheduler );
// Resolve
auto app = std::make_shared< DelveryService >( sormComponent, puComponent, transportLayer, ioController );
app.Start();
// Release
app.Release();
}
IoC контейнеры
Регистрация реализации для интерфейса
Разрешают необходимые зависимости
Выполняют авто связывание
Hypodermic
int main()
{
// Register
ContainerBuilder builder;
builder.registerType< Heater >().as< IHeater >();
builder.registerType< Pump >().as< IPump >();
builder.registerType< CoffeMaker >(
CREATE( std::make_shared< CoffeMaker >(
INJECT( IHeater ),
INJECT( IPump ) ) ) );
auto container = builder.build();
// Resolve
auto coffeMaker = container->resolve< CoffeMaker >();
coffeMaker->MakeCoffe();
}
Регистрация типа
{
ContainerBuilder builder;
// Регистрация непосредственно имплементации
builder.registerType< Pump >();
auto container = builder.build();
auto pump = container->resolve< Pump >();
ASSERT_TRUE( pump != nullptr );
}
Регистрация типа
{
ContainerBuilder builder;
// Регистрация по интерфейсу
builder.registerType< Pump >().as< IPump >();
auto container = builder.build();
auto pump= container->resolve< IPump >();
ASSERT_TRUE( pump != nullptr );
}
Регистрация типа
{
ContainerBuilder builder;
// Регистрация по интерфейсу и непосредственно имплементации
builder.registerType< Pump >().as< IPump >().asSelf();
auto container = builder.build();
auto concreetePump = container->resolve< Pump >();
auto abstractPump = container->resolve< IPump >();
ASSERT_TRUE( concreetePump != nullptr );
ASSERT_TRUE( abstractPump != nullptr );
}
Регистрация типа
{
ContainerBuilder builder;
// Регистрация экземпляра
auto pump = std::make_shared< Pump >();
builder.registerInstance( pump );
auto container = builder.build();
auto samePump = container->resolve< IPump >();
ASSERT_TRUE( samePump == pump );
}
Регистрация типа
{
ContainerBuilder builder;
// SingleInstance
builder.registerType< Pump >().as< IPump >().singleInstance();
auto container = builder.build();
auto pump = container->resolve< IPump >();
auto samePump = container->resolve< IPump >();
ASSERT_TRUE( samePump == pump );
}
Регистрация типа
{
ContainerBuilder builder;
// Регистрация одной имплементации по нескольким интерфейсам
builder.registerType< PumpAndHeater >().as< IPump >().as< IHeater >();
auto container = builder.build();
auto pump = container->resolve< IPump >();
auto heater = container->resolve< IHeater>();
// Опустим cast-ы для наглядности
ASSERT_TRUE( heater == pump );
}
Именованная регистрация типа
{
ContainerBuilder builder;
auto pump1 = std::make_shared< Pump >();
auto pump2 = std::make_shared< Pump >();
builder.registerInstance( pump1 ).named< IPump >( "pump1" );
builder.registerInstance( pump2 ).named< IPump >( "pump2" );
auto container = builder.build();
ASSERT_TRUE( container->resolveNamed< IPump >( "pump1" ) == pump1 );
ASSERT_TRUE( container->resolveNamed< IPump >( "pump2" ) == pump2 );
}
Инжекция зависимостей
{
ContainerBuilder builder;
builder.registerType< Pump >().as< IPump >();
builder.registerType< Heater >().as< IHeater >();
builder.registerType< CoffeMaker >(
CREATE( std::make_shared< CoffeMaker >(
INJECT( IHeater ),
INJECT( IPump ) ) ) ).as< CoffeMaker >();
auto container = builder.build();
auto coffeMaker = container->resolve< CoffeMaker >();
ASSERT_TRUE( coffeMaker != nullptr );
}
Инжекция зависимостей
{
ContainerBuilder builder;
builder.registerType< Pump >().named< IPump >( "pump" );
builder.registerType< Heater >().named< IHeater >( "heater" );
builder.registerType< CoffeMaker >(
CREATE( std::make_shared< CoffeMaker >(
INJECT_NAMED( IHeater, "heater" ),
INJECT_NAMED( IPump, "pump" ) ) ) ).as< CoffeMaker >();
auto container = builder.build();
auto coffeMaker = container->resolve< CoffeMaker >();
ASSERT_TRUE( coffeMaker != nullptr );
}
Регистрация через автосвязывание
struct ServiceA : IServiceA {
typedef AutowiredConstructor< ServiceA() > AutowiredSignature;
...
};
struct ServiceB : IServiceB {
typedef AutowiredConstructor< ServiceB(IServiceA*) > AutowiredSignature;
ServiceB( std::shared_ptr< IServiceA > serviceA )
: serviceA_( serviceA )
{
}
private:
std::shared_ptr< IServiceA > serviceA_;
};
Resolve через автосвязывание
{
ContainerBuilder builder;
builder.autowireType< ServiceA >().as< IServiceA >();
builder.autowireType< ServiceB >().singleInstance();
auto container = c.build();
auto serviceB = container->resolve< ServiceB >();
ASSERT_TRUE( serviceB != nullptr );
}
Как решать проблемы связывания?
Кидать исключение если зависимость не
задана
Кидать исключение если зависимость nullptr
Статика и динамика в IoC
IoC контейнеры позволяют создать каркас
приложения
IoC контейнеры не нужно передавать в
классы
Итоги:
DI в C++ вполне работает
Есть своя специфика в C++ и всегда нужно
держать ее в голове
Подход нужно рассматривать комплексно
Другие IoC контейнеры:
boost::di - header only!
walaroo
Как можно облегчить себе жизнь?
Для GMOCK есть python скрипт для
генерации кода моков
TypemockIsolator++
TEST( CoffeMakerTest, Should_heat_and_drip_water )
{
auto mockPump = FAKE< IPump >();
auto mockHeater = FAKE< IHeater >();
// Код теста...
}
TEST_F( IsolatorPPTests, IsExpired_YearIs2018_ReturnTrue )
{
Product product;
// Подготавливаем время для теста
SYSTEMTIME fakeTime;
fakeTime.wYear = 2018;
// Подделываем вызов системной функции
FAKE_GLOBAL( GetSystemTime );
WHEN_CALLED( GetSystemTime( RET( &fakeTime ) ) ).Ignore();
ASSERT_TRUE(product.IsExpired());
}
TypemockIsolator++
Для legacy кода.
Только Windows :(
А теперь вопросы
?

More Related Content

What's hot

Parallel STL
Parallel STLParallel STL
Parallel STL
Evgeny Krutko
 
Как за час сделать недельную работу
Как за час сделать недельную работуКак за час сделать недельную работу
Как за час сделать недельную работу
corehard_by
 
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведенияДракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
Platonov Sergey
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Yauheni Akhotnikau
 
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Sergey Platonov
 
Антон Полухин, Немного о Boost
Антон Полухин, Немного о BoostАнтон Полухин, Немного о Boost
Антон Полухин, Немного о Boost
Sergey Platonov
 
Использование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиИспользование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработки
victor-yastrebov
 
Догнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castДогнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_cast
Roman Orlov
 
Как перестать отлаживать асинхронный код и начать жить / Андрей Саломатин (Pr...
Как перестать отлаживать асинхронный код и начать жить / Андрей Саломатин (Pr...Как перестать отлаживать асинхронный код и начать жить / Андрей Саломатин (Pr...
Как перестать отлаживать асинхронный код и начать жить / Андрей Саломатин (Pr...
Ontico
 
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Platonov Sergey
 
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
Tatyanazaxarova
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладка
Sergey Platonov
 
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptСергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Sergey Platonov
 
Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++
Sergey Platonov
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templates
Platonov Sergey
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода
Pavel Tsukanov
 
Евгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияЕвгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализация
Platonov Sergey
 
Современный статический анализ кода: что умеет он, чего не умели линтеры
Современный статический анализ кода: что умеет он, чего не умели линтерыСовременный статический анализ кода: что умеет он, чего не умели линтеры
Современный статический анализ кода: что умеет он, чего не умели линтеры
corehard_by
 
Григорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптерГригорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптер
Sergey Platonov
 

What's hot (19)

Parallel STL
Parallel STLParallel STL
Parallel STL
 
Как за час сделать недельную работу
Как за час сделать недельную работуКак за час сделать недельную работу
Как за час сделать недельную работу
 
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведенияДракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведения
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?
 
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
 
Антон Полухин, Немного о Boost
Антон Полухин, Немного о BoostАнтон Полухин, Немного о Boost
Антон Полухин, Немного о Boost
 
Использование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиИспользование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработки
 
Догнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_castДогнать и перегнать boost::lexical_cast
Догнать и перегнать boost::lexical_cast
 
Как перестать отлаживать асинхронный код и начать жить / Андрей Саломатин (Pr...
Как перестать отлаживать асинхронный код и начать жить / Андрей Саломатин (Pr...Как перестать отлаживать асинхронный код и начать жить / Андрей Саломатин (Pr...
Как перестать отлаживать асинхронный код и начать жить / Андрей Саломатин (Pr...
 
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
 
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
Сравнение статического анализа общего назначения из Visual Studio 2010 и PVS-...
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладка
 
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptСергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и Javascript
 
Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++Борис Сазонов, RAII потоки и CancellationToken в C++
Борис Сазонов, RAII потоки и CancellationToken в C++
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templates
 
Статический анализ кода
Статический анализ кода Статический анализ кода
Статический анализ кода
 
Евгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализацияЕвгений Зуев, С++ в России: Стандарт языка и его реализация
Евгений Зуев, С++ в России: Стандарт языка и его реализация
 
Современный статический анализ кода: что умеет он, чего не умели линтеры
Современный статический анализ кода: что умеет он, чего не умели линтерыСовременный статический анализ кода: что умеет он, чего не умели линтеры
Современный статический анализ кода: что умеет он, чего не умели линтеры
 
Григорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптерГригорий Демченко, Универсальный адаптер
Григорий Демченко, Универсальный адаптер
 

Viewers also liked

Василий Сорокин, “Google C++ Mocking and Test Frameworks”
Василий Сорокин, “Google C++ Mocking and Test Frameworks”Василий Сорокин, “Google C++ Mocking and Test Frameworks”
Василий Сорокин, “Google C++ Mocking and Test Frameworks”
Platonov Sergey
 
Практика использования Dependency Injection
Практика использования Dependency InjectionПрактика использования Dependency Injection
Практика использования Dependency Injection
Platonov Sergey
 
Unit-Testing Bad-Practices by Example
Unit-Testing Bad-Practices by ExampleUnit-Testing Bad-Practices by Example
Unit-Testing Bad-Practices by ExampleBenjamin Eberlei
 
One definition rule - что это такое, и как с этим жить
One definition rule - что это такое, и как с этим житьOne definition rule - что это такое, и как с этим жить
One definition rule - что это такое, и как с этим жить
Platonov Sergey
 
Использование maven для сборки больших модульных c++ проектов на примере Odin...
Использование maven для сборки больших модульных c++ проектов на примере Odin...Использование maven для сборки больших модульных c++ проектов на примере Odin...
Использование maven для сборки больших модульных c++ проектов на примере Odin...
Platonov Sergey
 
Павел Филонов, Разделяй и управляй вместе с Conan.io
Павел Филонов, Разделяй и управляй вместе с Conan.ioПавел Филонов, Разделяй и управляй вместе с Conan.io
Павел Филонов, Разделяй и управляй вместе с Conan.io
Sergey Platonov
 
Practical unit testing in c & c++
Practical unit testing in c & c++Practical unit testing in c & c++
Practical unit testing in c & c++
Matt Hargett
 
Как писать красивый код или основы SOLID
Как писать красивый код или основы SOLIDКак писать красивый код или основы SOLID
Как писать красивый код или основы SOLID
Pavel Tsukanov
 
Clean Unit Test Patterns
Clean Unit Test PatternsClean Unit Test Patterns
Clean Unit Test Patterns
Frank Appel
 
Concepts lite
Concepts liteConcepts lite
Concepts lite
Platonov Sergey
 
Визуализация автомобильных маршрутов
Визуализация автомобильных маршрутовВизуализация автомобильных маршрутов
Визуализация автомобильных маршрутов
Platonov Sergey
 
Функциональный микроскоп: линзы в C++
Функциональный микроскоп: линзы в C++Функциональный микроскоп: линзы в C++
Функциональный микроскоп: линзы в C++
Platonov Sergey
 
Ranges calendar-novosibirsk-2015-08
Ranges calendar-novosibirsk-2015-08Ranges calendar-novosibirsk-2015-08
Ranges calendar-novosibirsk-2015-08
Platonov Sergey
 
HPX: C++11 runtime система для параллельных и распределённых вычислений
HPX: C++11 runtime система для параллельных и распределённых вычисленийHPX: C++11 runtime система для параллельных и распределённых вычислений
HPX: C++11 runtime система для параллельных и распределённых вычислений
Platonov Sergey
 

Viewers also liked (14)

Василий Сорокин, “Google C++ Mocking and Test Frameworks”
Василий Сорокин, “Google C++ Mocking and Test Frameworks”Василий Сорокин, “Google C++ Mocking and Test Frameworks”
Василий Сорокин, “Google C++ Mocking and Test Frameworks”
 
Практика использования Dependency Injection
Практика использования Dependency InjectionПрактика использования Dependency Injection
Практика использования Dependency Injection
 
Unit-Testing Bad-Practices by Example
Unit-Testing Bad-Practices by ExampleUnit-Testing Bad-Practices by Example
Unit-Testing Bad-Practices by Example
 
One definition rule - что это такое, и как с этим жить
One definition rule - что это такое, и как с этим житьOne definition rule - что это такое, и как с этим жить
One definition rule - что это такое, и как с этим жить
 
Использование maven для сборки больших модульных c++ проектов на примере Odin...
Использование maven для сборки больших модульных c++ проектов на примере Odin...Использование maven для сборки больших модульных c++ проектов на примере Odin...
Использование maven для сборки больших модульных c++ проектов на примере Odin...
 
Павел Филонов, Разделяй и управляй вместе с Conan.io
Павел Филонов, Разделяй и управляй вместе с Conan.ioПавел Филонов, Разделяй и управляй вместе с Conan.io
Павел Филонов, Разделяй и управляй вместе с Conan.io
 
Practical unit testing in c & c++
Practical unit testing in c & c++Practical unit testing in c & c++
Practical unit testing in c & c++
 
Как писать красивый код или основы SOLID
Как писать красивый код или основы SOLIDКак писать красивый код или основы SOLID
Как писать красивый код или основы SOLID
 
Clean Unit Test Patterns
Clean Unit Test PatternsClean Unit Test Patterns
Clean Unit Test Patterns
 
Concepts lite
Concepts liteConcepts lite
Concepts lite
 
Визуализация автомобильных маршрутов
Визуализация автомобильных маршрутовВизуализация автомобильных маршрутов
Визуализация автомобильных маршрутов
 
Функциональный микроскоп: линзы в C++
Функциональный микроскоп: линзы в C++Функциональный микроскоп: линзы в C++
Функциональный микроскоп: линзы в C++
 
Ranges calendar-novosibirsk-2015-08
Ranges calendar-novosibirsk-2015-08Ranges calendar-novosibirsk-2015-08
Ranges calendar-novosibirsk-2015-08
 
HPX: C++11 runtime система для параллельных и распределённых вычислений
HPX: C++11 runtime система для параллельных и распределённых вычисленийHPX: C++11 runtime система для параллельных и распределённых вычислений
HPX: C++11 runtime система для параллельных и распределённых вычислений
 

Similar to DI в C++ тонкости и нюансы

Парсим и кодогенерируем для С++ с использованием clang
Парсим и кодогенерируем для С++ с использованием clangПарсим и кодогенерируем для С++ с использованием clang
Парсим и кодогенерируем для С++ с использованием clang
corehard_by
 
20090720 hpc exercise1
20090720 hpc exercise120090720 hpc exercise1
20090720 hpc exercise1Michael Karpov
 
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
Yandex
 
паттерны программирования
паттерны программированияпаттерны программирования
паттерны программированияguestfc8ae0
 
UA Mobile 2012
UA Mobile 2012UA Mobile 2012
UA Mobile 2012
dmalykhanov
 
Уменьшение влияния человеческого фактора при разработке бизнес приложений
Уменьшение влияния человеческого фактора при разработке бизнес приложенийУменьшение влияния человеческого фактора при разработке бизнес приложений
Уменьшение влияния человеческого фактора при разработке бизнес приложений
ngrebnev
 
Code Contracts ABC 16.04.2011
Code Contracts ABC 16.04.2011Code Contracts ABC 16.04.2011
Code Contracts ABC 16.04.2011Dmytro Mindra
 
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Denis Tsvettsih
 
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.
Fedor Malyshkin
 
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Yandex
 
отладка Mpi приложений
отладка Mpi приложенийотладка Mpi приложений
отладка Mpi приложенийMichael Karpov
 
Cpp0x Introduction
Cpp0x IntroductionCpp0x Introduction
Cpp0x Introduction
Fedor Vompe
 
Cтатический анализ кода (на примере DDD-фреймворка)
Cтатический анализ кода (на примере DDD-фреймворка)Cтатический анализ кода (на примере DDD-фреймворка)
Cтатический анализ кода (на примере DDD-фреймворка)
ngrebnev
 
Design Principles
Design PrinciplesDesign Principles
Design Principles
Alexander Konduforov
 
Mobile Fest#spb 2012
Mobile Fest#spb 2012Mobile Fest#spb 2012
Mobile Fest#spb 2012
dmalykhanov
 
Асинхронность и сопрограммы
Асинхронность и сопрограммыАсинхронность и сопрограммы
Асинхронность и сопрограммы
Platonov Sergey
 
Step cpp022
Step cpp022Step cpp022
Step cpp022
Evgenij Laktionov
 
Cтиль программирования
Cтиль программированияCтиль программирования
Cтиль программирования
Constantin Kichinsky
 
Основы и применение статического анализа кода при разработке лекция 1
Основы и применение статического анализа кода при разработке лекция 1Основы и применение статического анализа кода при разработке лекция 1
Основы и применение статического анализа кода при разработке лекция 1
m2rus
 
Asynchrony and coroutines
Asynchrony and coroutinesAsynchrony and coroutines
Asynchrony and coroutines
corehard_by
 

Similar to DI в C++ тонкости и нюансы (20)

Парсим и кодогенерируем для С++ с использованием clang
Парсим и кодогенерируем для С++ с использованием clangПарсим и кодогенерируем для С++ с использованием clang
Парсим и кодогенерируем для С++ с использованием clang
 
20090720 hpc exercise1
20090720 hpc exercise120090720 hpc exercise1
20090720 hpc exercise1
 
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...
 
паттерны программирования
паттерны программированияпаттерны программирования
паттерны программирования
 
UA Mobile 2012
UA Mobile 2012UA Mobile 2012
UA Mobile 2012
 
Уменьшение влияния человеческого фактора при разработке бизнес приложений
Уменьшение влияния человеческого фактора при разработке бизнес приложенийУменьшение влияния человеческого фактора при разработке бизнес приложений
Уменьшение влияния человеческого фактора при разработке бизнес приложений
 
Code Contracts ABC 16.04.2011
Code Contracts ABC 16.04.2011Code Contracts ABC 16.04.2011
Code Contracts ABC 16.04.2011
 
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
 
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.
 
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
 
отладка Mpi приложений
отладка Mpi приложенийотладка Mpi приложений
отладка Mpi приложений
 
Cpp0x Introduction
Cpp0x IntroductionCpp0x Introduction
Cpp0x Introduction
 
Cтатический анализ кода (на примере DDD-фреймворка)
Cтатический анализ кода (на примере DDD-фреймворка)Cтатический анализ кода (на примере DDD-фреймворка)
Cтатический анализ кода (на примере DDD-фреймворка)
 
Design Principles
Design PrinciplesDesign Principles
Design Principles
 
Mobile Fest#spb 2012
Mobile Fest#spb 2012Mobile Fest#spb 2012
Mobile Fest#spb 2012
 
Асинхронность и сопрограммы
Асинхронность и сопрограммыАсинхронность и сопрограммы
Асинхронность и сопрограммы
 
Step cpp022
Step cpp022Step cpp022
Step cpp022
 
Cтиль программирования
Cтиль программированияCтиль программирования
Cтиль программирования
 
Основы и применение статического анализа кода при разработке лекция 1
Основы и применение статического анализа кода при разработке лекция 1Основы и применение статического анализа кода при разработке лекция 1
Основы и применение статического анализа кода при разработке лекция 1
 
Asynchrony and coroutines
Asynchrony and coroutinesAsynchrony and coroutines
Asynchrony and coroutines
 

More from Platonov Sergey

Алексей Кутумов, C++ без исключений, часть 3
Алексей Кутумов,  C++ без исключений, часть 3Алексей Кутумов,  C++ без исключений, часть 3
Алексей Кутумов, C++ без исключений, часть 3
Platonov Sergey
 
Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.
Platonov Sergey
 
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговлеТененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
Platonov Sergey
 
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на LinuxПавел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Platonov Sergey
 
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IIДмитрий Кашицын, Вывод типов в динамических и не очень языках II
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
Platonov Sergey
 
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IДмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
Platonov Sergey
 
QML\Qt Quick на практике
QML\Qt Quick на практикеQML\Qt Quick на практике
QML\Qt Quick на практике
Platonov Sergey
 
Денис Кормалев Метаобъектная система Qt
Денис Кормалев Метаобъектная система QtДенис Кормалев Метаобъектная система Qt
Денис Кормалев Метаобъектная система Qt
Platonov Sergey
 
Максим Хижинский Lock-free maps
Максим Хижинский Lock-free mapsМаксим Хижинский Lock-free maps
Максим Хижинский Lock-free maps
Platonov Sergey
 
Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...
Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...
Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...
Platonov Sergey
 
High quality library from scratch
High quality library from scratchHigh quality library from scratch
High quality library from scratch
Platonov Sergey
 
С++ without new and delete
С++ without new and deleteС++ without new and delete
С++ without new and delete
Platonov Sergey
 
Categories for the Working C++ Programmer
Categories for the Working C++ ProgrammerCategories for the Working C++ Programmer
Categories for the Working C++ ProgrammerPlatonov Sergey
 
Библиотека Boost с нуля на примере Boost.DLL
Библиотека Boost с нуля на примере Boost.DLLБиблиотека Boost с нуля на примере Boost.DLL
Библиотека Boost с нуля на примере Boost.DLL
Platonov Sergey
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesPlatonov Sergey
 
Практика Lock-free. RealTime-сервер
Практика Lock-free. RealTime-серверПрактика Lock-free. RealTime-сервер
Практика Lock-free. RealTime-сервер
Platonov Sergey
 
С++ without new and delete
С++ without new and deleteС++ without new and delete
С++ without new and delete
Platonov Sergey
 

More from Platonov Sergey (17)

Алексей Кутумов, C++ без исключений, часть 3
Алексей Кутумов,  C++ без исключений, часть 3Алексей Кутумов,  C++ без исключений, часть 3
Алексей Кутумов, C++ без исключений, часть 3
 
Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.Евгений Крутько, Многопоточные вычисления, современный подход.
Евгений Крутько, Многопоточные вычисления, современный подход.
 
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговлеТененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
 
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на LinuxПавел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
Павел Беликов, Опыт мигрирования крупного проекта с Windows-only на Linux
 
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IIДмитрий Кашицын, Вывод типов в динамических и не очень языках II
Дмитрий Кашицын, Вывод типов в динамических и не очень языках II
 
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках IДмитрий Кашицын, Вывод типов в динамических и не очень языках I
Дмитрий Кашицын, Вывод типов в динамических и не очень языках I
 
QML\Qt Quick на практике
QML\Qt Quick на практикеQML\Qt Quick на практике
QML\Qt Quick на практике
 
Денис Кормалев Метаобъектная система Qt
Денис Кормалев Метаобъектная система QtДенис Кормалев Метаобъектная система Qt
Денис Кормалев Метаобъектная система Qt
 
Максим Хижинский Lock-free maps
Максим Хижинский Lock-free mapsМаксим Хижинский Lock-free maps
Максим Хижинский Lock-free maps
 
Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...
Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...
Владислав Шаклеин. Смешивание управляемого и неуправляемого C++ кода в Micros...
 
High quality library from scratch
High quality library from scratchHigh quality library from scratch
High quality library from scratch
 
С++ without new and delete
С++ without new and deleteС++ without new and delete
С++ without new and delete
 
Categories for the Working C++ Programmer
Categories for the Working C++ ProgrammerCategories for the Working C++ Programmer
Categories for the Working C++ Programmer
 
Библиотека Boost с нуля на примере Boost.DLL
Библиотека Boost с нуля на примере Boost.DLLБиблиотека Boost с нуля на примере Boost.DLL
Библиотека Boost с нуля на примере Boost.DLL
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templates
 
Практика Lock-free. RealTime-сервер
Практика Lock-free. RealTime-серверПрактика Lock-free. RealTime-сервер
Практика Lock-free. RealTime-сервер
 
С++ without new and delete
С++ without new and deleteС++ without new and delete
С++ without new and delete
 

DI в C++ тонкости и нюансы

  • 1. DI в C++ тонкости и нюансы а так же IoC контейнеры на примере Hypodermic Щербаков Антон компания СИГНАТЕК
  • 2. Обо мне: - решения в области СОРМ и телекоммуникаций - 24x7 сервисы с минимум GUI - непрерывное усиление и развитие команды
  • 3. О презентации: - личный опыт использования DI и IoC - примеры тестов на GMOCK и GTEST - … и c++ :)
  • 4. Специфика работы - Много долгоживущих проектов - Которые нужно дорабатывать - Дорабатывать быстро и качественно
  • 5. С чего все начиналось...
  • 6. Выводы: Код должен быть тестируем Код должен быть тестируем просто Тестовое окружение должно быть максимально простым
  • 7. Что же такое DI? ...Кто слышал?
  • 8. Dependency Injection это design pattern ● Dependency это объект, который используется (Service) ● Injection - передача зависимости, зависящему классу (Client-у). При этом Dependency становится состоянием класса.
  • 9. Пример с кофеваркой /* Без внедрения зависимостей */ class CoffeMaker { public: CoffeMaker() { m_heater = new Heater(); m_pump = new Pump(); } Coffe MakeCoffe() { /* ... */ } private: Heater* m_heater; Pump* m_pump; }; int main() { CoffeMaker* coffeMaker = new CoffeMaker(); coffeMaker->MakeCoffe(); } /* Ручное внедрение зависимостей */ class CoffeMaker { public: CoffeMaker( Heater* heater, Pump* pump ) { m_heater = heater; m_pump = pump; } Coffe MakeCoffe() { /* ... */ } private: Heater* m_heater; Pump* m_pump; }; int main() { Heater* heater = new Heater(); Pump* pump = new Pump(); CoffeMaker* coffeMaker = new CoffeMaker( heater, pump ); coffeMaker->MakeCoffe(); }
  • 10. class Heater : public IHeater { public: virtual void Heat() = 0; }; class Pump : public IPump { public: virtual void Drip() = 0; }; class CoffeMaker { public: CoffeMaker( IHeater* heater, IPump* pump ) { m_heater = heater; m_pump = pump; } Coffe MakeCoffe() { /* ... */ } private: IHeater* m_heater; IPump* m_pump; }; int main() { // Пользователь класса определяет что именно передавать IHeater* heater = new Heater(); IPump* pump = new Pump(); CoffeMaker* coffeMaker = new CoffeMaker( heater, pump ); coffeMaker->MakeCoffe(); }
  • 11. Что получаем? Кого инстанциировать решает пользователь (MOCK, STUB) Получаем слабою связность Класс стал проще тестироваться
  • 12. class Mock_IHeater : public IHeater { public: MOCK_METHOD0( Heat, void() ); }; class Mock_IPump : public IPump { public: MOCK_METHOD0( Drip, void() ); }; TEST_F( CoffeMakerTest, Should_heat_water ) { Mock_IHeater heater; Mock_IPump pump; CoffeMaker coffeMaker( &heater, &pump ); EXPECT_CALL( pump, Drip() ) .Times( 1 ); EXPECT_CALL( heater, Heat() ) .Times( 1 ); coffeMaker.MakeCoffe(); }
  • 13. Минусы? Избыточный дизайн (чем как правило нужно) “Архитектурный” шум в виде интерфейсов НО тестируемость важнее!
  • 14. Зависимость через указатель Как контролировать потерю объекта? А при многопоточности? Кто отвечает за время жизни зависимости? Чистые указатели - это уже дурной тон
  • 16. unique_ptr Только класс клиент владеет и отвечает за время жизни зависимоости. Но тестировать не получится поэтому unique_ptr
  • 17. shared_ptr Класс клиент так же отвечает за время жизни Или ответственность передана полностью Потокобезопасен НО есть проблема с циклическими связями
  • 18. weak_ptr За время жизни класс не отвечает и готов к тому, что ее могут отнять
  • 19. В качестве способа передачи зависимости остались: shared_ptr weak_ptr
  • 21. class CoffeMaker { public: CoffeMaker( std::shared_ptr< IHeater > heater, std::shared_ptr< IPump > pump ) { m_heater = heater; m_pump = pump; } void SetBell( std::weak_ptr< IBell > bell ) { m_bell = bell; } Coffe MakeCoffe() { /* ... */ } private: std::shared_ptr< IHeater > m_heater; // Класс не может делать кофе без насоса и нагревателя std::shared_ptr< IPump > m_pump; std::weak_ptr< IBell > m_bell; // Класс может делать кофе и без колокольчика }; Внедряем зависимости с weak_ptr
  • 22. При DI лучше обходиться без weak_ptr Циклические связи - плохой “запах” в архитектуре и дизайне
  • 23. class CoffeMaker { public: CoffeMaker( std::shared_ptr< IHeater > heater, std::shared_ptr< IPump > pump ) { m_heater = heater; m_pump = pump; } /* ... */ private: std::shared_ptr< IHeater > m_heater; std::shared_ptr< IPump > m_pump; }; TEST_F( CoffeMakerTest, Should_heat_water ) { std::shared_ptr< IHeater > heater = std::make_shared< Mock_IHeater >(); std::shared_ptr< IPump > pump = std::make_shared< Mock_IPump >(); CoffeMaker coffeMaker( heater, pump ); EXPECT_CALL( *pump, Drip() ) .Times( 1 ); EXPECT_CALL( *heater, Heat() ) .Times( 1 ); coffeMaker.MakeCoffe(); }
  • 24. Все хорошо… НО Кто все это будет конструировать? А внедрять зависимости? И как это проверять?
  • 25. Пример ручного связывания { auto transportLayer = std::make_shared< TcpTransportSystem >(); auto sormController = std::make_shared< SormControllerComponent >( sormType, acceptTimeOut ); auto sormMsgProcessor = std::make_shared< SormMsgProcessor >(); auto sormTransport = std::make_shared< TcpTransport >( transportLayer sormIp, sormPort, sormMessageProcessor ); auto sormComponent = std::make_shared< SormComponent >( sormType, sormController, sormTransport ); auto puTranspoort = std::make_shared< TcpTransport >( puIp, puPort, sormMessageProcessor ); auto puComponent = std::make_shared< PuModule >( puTransport ); auto operationScheduler = std::make_shared< RealTimeOperationScheduler >(); auto ioController = std::make_shared< IoController >( operationScheduler ); auto app = std::make_shared< DelveryService >( sormComponent, puComponent, transportLayer, ioController ); app.Start(); app.Release(); }
  • 26. Composition root и Register Resolve Release { // Register auto transportLayer = std::make_shared< TcpTransportSystem >(); auto sormController = std::make_shared< SormControllerComponent >( sormType, acceptTimeOut ); auto sormMsgProcessor = std::make_shared< SormMsgProcessor >(); auto sormTransport = std::make_shared< TcpTransport >( transportLayer sormIp, sormPort, sormMessageProcessor ); auto sormComponent = std::make_shared< SormComponent >( sormType, sormController, sormTransport ); auto puTranspoort = std::make_shared< TcpTransport >( puIp, puPort, sormMessageProcessor ); auto puComponent = std::make_shared< PuModule >( puTransport ); auto operationScheduler = std::make_shared< RealTimeOperationScheduler >(); auto ioController = std::make_shared< IoController >( operationScheduler ); // Resolve auto app = std::make_shared< DelveryService >( sormComponent, puComponent, transportLayer, ioController ); app.Start(); // Release app.Release(); }
  • 27. IoC контейнеры Регистрация реализации для интерфейса Разрешают необходимые зависимости Выполняют авто связывание
  • 28. Hypodermic int main() { // Register ContainerBuilder builder; builder.registerType< Heater >().as< IHeater >(); builder.registerType< Pump >().as< IPump >(); builder.registerType< CoffeMaker >( CREATE( std::make_shared< CoffeMaker >( INJECT( IHeater ), INJECT( IPump ) ) ) ); auto container = builder.build(); // Resolve auto coffeMaker = container->resolve< CoffeMaker >(); coffeMaker->MakeCoffe(); }
  • 29. Регистрация типа { ContainerBuilder builder; // Регистрация непосредственно имплементации builder.registerType< Pump >(); auto container = builder.build(); auto pump = container->resolve< Pump >(); ASSERT_TRUE( pump != nullptr ); }
  • 30. Регистрация типа { ContainerBuilder builder; // Регистрация по интерфейсу builder.registerType< Pump >().as< IPump >(); auto container = builder.build(); auto pump= container->resolve< IPump >(); ASSERT_TRUE( pump != nullptr ); }
  • 31. Регистрация типа { ContainerBuilder builder; // Регистрация по интерфейсу и непосредственно имплементации builder.registerType< Pump >().as< IPump >().asSelf(); auto container = builder.build(); auto concreetePump = container->resolve< Pump >(); auto abstractPump = container->resolve< IPump >(); ASSERT_TRUE( concreetePump != nullptr ); ASSERT_TRUE( abstractPump != nullptr ); }
  • 32. Регистрация типа { ContainerBuilder builder; // Регистрация экземпляра auto pump = std::make_shared< Pump >(); builder.registerInstance( pump ); auto container = builder.build(); auto samePump = container->resolve< IPump >(); ASSERT_TRUE( samePump == pump ); }
  • 33. Регистрация типа { ContainerBuilder builder; // SingleInstance builder.registerType< Pump >().as< IPump >().singleInstance(); auto container = builder.build(); auto pump = container->resolve< IPump >(); auto samePump = container->resolve< IPump >(); ASSERT_TRUE( samePump == pump ); }
  • 34. Регистрация типа { ContainerBuilder builder; // Регистрация одной имплементации по нескольким интерфейсам builder.registerType< PumpAndHeater >().as< IPump >().as< IHeater >(); auto container = builder.build(); auto pump = container->resolve< IPump >(); auto heater = container->resolve< IHeater>(); // Опустим cast-ы для наглядности ASSERT_TRUE( heater == pump ); }
  • 35. Именованная регистрация типа { ContainerBuilder builder; auto pump1 = std::make_shared< Pump >(); auto pump2 = std::make_shared< Pump >(); builder.registerInstance( pump1 ).named< IPump >( "pump1" ); builder.registerInstance( pump2 ).named< IPump >( "pump2" ); auto container = builder.build(); ASSERT_TRUE( container->resolveNamed< IPump >( "pump1" ) == pump1 ); ASSERT_TRUE( container->resolveNamed< IPump >( "pump2" ) == pump2 ); }
  • 36. Инжекция зависимостей { ContainerBuilder builder; builder.registerType< Pump >().as< IPump >(); builder.registerType< Heater >().as< IHeater >(); builder.registerType< CoffeMaker >( CREATE( std::make_shared< CoffeMaker >( INJECT( IHeater ), INJECT( IPump ) ) ) ).as< CoffeMaker >(); auto container = builder.build(); auto coffeMaker = container->resolve< CoffeMaker >(); ASSERT_TRUE( coffeMaker != nullptr ); }
  • 37. Инжекция зависимостей { ContainerBuilder builder; builder.registerType< Pump >().named< IPump >( "pump" ); builder.registerType< Heater >().named< IHeater >( "heater" ); builder.registerType< CoffeMaker >( CREATE( std::make_shared< CoffeMaker >( INJECT_NAMED( IHeater, "heater" ), INJECT_NAMED( IPump, "pump" ) ) ) ).as< CoffeMaker >(); auto container = builder.build(); auto coffeMaker = container->resolve< CoffeMaker >(); ASSERT_TRUE( coffeMaker != nullptr ); }
  • 38. Регистрация через автосвязывание struct ServiceA : IServiceA { typedef AutowiredConstructor< ServiceA() > AutowiredSignature; ... }; struct ServiceB : IServiceB { typedef AutowiredConstructor< ServiceB(IServiceA*) > AutowiredSignature; ServiceB( std::shared_ptr< IServiceA > serviceA ) : serviceA_( serviceA ) { } private: std::shared_ptr< IServiceA > serviceA_; };
  • 39. Resolve через автосвязывание { ContainerBuilder builder; builder.autowireType< ServiceA >().as< IServiceA >(); builder.autowireType< ServiceB >().singleInstance(); auto container = c.build(); auto serviceB = container->resolve< ServiceB >(); ASSERT_TRUE( serviceB != nullptr ); }
  • 40. Как решать проблемы связывания? Кидать исключение если зависимость не задана Кидать исключение если зависимость nullptr
  • 41. Статика и динамика в IoC IoC контейнеры позволяют создать каркас приложения IoC контейнеры не нужно передавать в классы
  • 42. Итоги: DI в C++ вполне работает Есть своя специфика в C++ и всегда нужно держать ее в голове Подход нужно рассматривать комплексно
  • 44. Как можно облегчить себе жизнь? Для GMOCK есть python скрипт для генерации кода моков
  • 45. TypemockIsolator++ TEST( CoffeMakerTest, Should_heat_and_drip_water ) { auto mockPump = FAKE< IPump >(); auto mockHeater = FAKE< IHeater >(); // Код теста... } TEST_F( IsolatorPPTests, IsExpired_YearIs2018_ReturnTrue ) { Product product; // Подготавливаем время для теста SYSTEMTIME fakeTime; fakeTime.wYear = 2018; // Подделываем вызов системной функции FAKE_GLOBAL( GetSystemTime ); WHEN_CALLED( GetSystemTime( RET( &fakeTime ) ) ).Ignore(); ASSERT_TRUE(product.IsExpired()); }