Практика использования dependency injection

Post on 18-Jul-2015

568 Views

Category:

Software

6 Downloads

Preview:

Click to see full reader

TRANSCRIPT

ПРАКТИКА ИСПОЛЬЗОВАНИЯ

DEPENDENCY INJECTIONВиктор Петров, к.ф.-м.н, старший разработчик,

Сергей Анпилов, ведущий разработчик,

при участии команды разработки Kaspersky Endpoint Security for Windows

1

Из опыта разработки новой версии Kaspersky Endpoint Security for Windows:

Использование Service Locator. Подводные камни;

Использование Dependency Injection. Подводные камни;

Обзор современных C++ DI-фреймворков. Перспективы;

Содержание

2

Java/C# разработчик и Dependency Injection

C++ разработчик и Dependency Injection

C++ разработчик и Dependency Injection на C++11/14

3

Service Locator (SL) и Dependency Injection (DI) – способы реализации

инверсии управления (Inversion of Control, IoC)

class VirusDetector{

shared_ptr<VirusBases> m_virusBases;

public:VirusDetector(){

m_virusBases = make_shared<VirusBases>();}...

};

Прямое управление

VirusDetectorC VirusBasesC

4

5

class VirusDetector{

shared_ptr<IVirusBases> m_virusBases;

public:explicit VirusDetector(

shared_ptr<IVirusBases> virusBases): m_virusBases(move(virusBases))

{}...

};

VirusDetectorC IVirusBasesI

VirusBasesC

6

Service Locator (SL) и Dependency Injection (DI) – способы реализации

инверсии управления (Inversion of Control, IoC)

Dependency Injection

7

VirusDetectorC

IVirusBasesI

VirusBasesC

class VirusDetector{

shared_ptr<IVirusBases> m_virusBases;

public:explicit VirusDetector(IServiceLocator* sl):

m_virusBases(sl->GetInterface(IID_OF(IVirusBases))){}...

};

IServiceLocatorI

ServiceLocatorC

8

Service Locator (SL) и Dependency Injection (DI) – способы реализации

инверсии управления (Inversion of Control, IoC)

Service Locator

9

Из опыта разработки новой версии Kaspersky Endpoint

Security for Windows:

Использование Service Locator. Подводные камни;

Использование Dependency Injection. Подводные камни;

Обзор современных C++ DI-фреймворков. Перспективы;

Содержание

10

Components

AVP Seamless Update Service

AVP AVPSUS

Updater

Firewall

Antimalware

Antivirus

DriverScheduler

Message

Queue

11

Использование Service Locator в AVPstruct IServiceLocator : public IObject{

virtual shared_ptr<IObject> GetInterface(iid_t iid) = 0;};

struct IObjectFactory : public IObject{

virtual shared_ptr<IObject> CreateInstance() = 0;};

<component name="VirusBases" clsid="0xfe1fe107" module="virus_bases.dll"><interface name="IVirusBases" iid="0x7996082a" />

</component>

shared_ptr<IObjectFactory> getObjectFactory(IServiceLocator*, clsid_t); // export

config

dll

source

12

AVP: получение списка зависимостей

Virus

Detector

GetInterface(IID_OF (IVirusBasesN), basesN)

Service Locator Component Dependency Injection Component

class VirusDetector{public:

VirusDetector(shared_ptr<IVirusBases1> bases1, ..., shared_ptr<IVirusBasesM> basesM);

...};

13

IDiskFormater* df

AVP: контроль используемых сервисов

Service Locator Component Dependency Injection Component

14

void UpdateBases(IServiceLocator* sl) {...OptimizeBasesFormat(sl);

}

void OptimizeBasesFormat(IServiceLocator* sl) {

}

// TODO: Defragment diskshared_ptr<IDiskFormater> diskFormater =sl->GetInterface(IID_OF(IDiskFormater));

diskFormater->Format("C:\\");

df

void UpdateBases(

...OptimizeBasesFormat(

}

) {

void OptimizeBasesFormat(

);

) {IDiskFormater* df

}

// TODO: Defragment diskdf->Format("C:\\");

AVP: unit-тестирование

Service Locator Component Dependency Injection Component

VirusDetectorC

IVirusBasesI

VirusBasesMockC

IServiceLocatorI

ServiceLocatorMockC

VirusDetectorC IVirusBasesI

VirusBasesMockC

См. также «получение списка зависимостей»15

DI в разных типах приложений

Service Locator Component Dependency Injection Component

SL

Application

DI

Application

Application

with SL of

another type

Non-IoC

Application

SL

Application

DI

Application

Application

with SL of

another type

Non-IoC

Application

Adapter

SL

component

DI

component

SL

component

SL

component

SL

component

Adapter Adapter

DI

component

DI

component

DI

component

16

AVPSUS: комбинирование DI и SL

template<typename T, typename... Deps>

shared_ptr<T> Adapter::CreateSLComponent(Deps... dependencies)

{

shared_ptr<IServiceLocator> sl = BuildServiceLocator(dependencies...);

shared_ptr<T> component = CreateObject<T>(sl);

return component;

}

DI application

Adapter SL component

17

Из опыта разработки новой версии Kaspersky Endpoint Security for Windows:

Использование Service Locator. Подводные камни;

Использование Dependency Injection. Подводные камни;

Обзор современных C++ DI-фреймворков. Перспективы;

Содержание

18

AVPSUS: Подводные камни DI

1. Объекты создаются всегда, вне зависимости от частоты использования

19

class VirusDetector {const shared_ptr<IVirusBases> m_virusBases;const shared_ptr<IRecoveryManager> m_recoveryManager;

public:VirusDetector(shared_ptr<IVirusBases> virusBases,

shared_ptr<IRecoveryManager> recoveryManager): m_virusBases(move(virusBases)), m_recoveryManager(move(recoveryManager)) {}

void DetectViruses() {try{/* Detect */}catch (const std::exception&){

m_recoveryManager->Recover();}

}};

2. Разрастание конструкторов - признак плохого дизайна.

class VirusDetector{public:

VirusDetector(IVirusBases* virusBases, IRecoveryManager* recoveryManager,IAntimalwareDetector* antimalwareDetector, IAntiRootkitDetector* antiRootkitDetector, IWebAnalyzer* webAnalyzer, IMailAnalyzer* mailAnalyzer, ITrafficProcessor* trafficProcessor, IBasesDownloader* basesDownloader, IBasesVerifier* basesVerifier, IWormsDetector* wormsDetector, IVulnerabilityDetector* vulnerabilityDetector, ITrojanDetector* trojanDetector, IStealthDetector* stealthDetector, ILicenseProvider* licenseProvider, ISettingsProvider* settingsProvider, IPhishingDetector* phishingDetector, IUrlFilter* urlFilter, IWoodPeckerDetector* woodPeckerDetector, IMacroVirusesDetector* macroVirusesDetector, IAntiBanner* antiBanner, ISystemWatcher* systemWatcher, IFileMonitor* fileMonitor, IRegistryMonitor* registryMonitor, INetworkMonitor* networkMonitor, IApplcationMonitor* applicationMonitor, IDeviceControl* deviceControl, IInstantMessengersMonitor* instantMessengersMonitor);

/*...*/};

20

AVPSUS: Подводные камни DI

3. Рост сложности конфигурации

void Configure(){

auto vbFactory = CreateVirusBasesFactory();auto vbConfig = LoadVirusBasesConfiguration();auto virusBases = vbFactory->CreateVirusBases(vbConfig);auto recoveryManager = TryCreateRecoveryManager();if (!recoveryManager)

LogWarningRecoveryManagerNotAvailable();auto amDetector = make_shared<AntimalwareDetector>(virusBases);auto arDetector = make_shared<AntiRootkitDetector>(virusBases, amDetector);auto webAnalyzer = make_shared<WebAnalyzer>(amDetector, recoveryManager);auto mailAnalyzer = make_shared<MailAnalyzer>(amDetector, recoveryManager, webAnalyzer);auto trafficProcessor = make_unique<TrafficProcessor>(arDetector, webAnalyzer, mailAnalyzer);// ...

}

21

AVPSUS: Подводные камни DI

Из опыта разработки новой версии Kaspersky Endpoint Security for Windows:

Использование Service Locator. Подводные камни;

Использование Dependency Injection. Подводные камни;

Обзор современных C++ DI-фреймворков.Перспективы;

Содержание

22

DI фреймворк: перспектива развития AVPSUS

DI фреймворк – средство конструирования объектов на основе

заданной конфигурации зависимостей.

Мотивация:

• Отделение конфигурации от логики;

• Декларативность описания конфигурации;

23

Технические требования:

• Простота конфигурирования компонентов;

• Явность списка зависимостей компонент;

• Обнаружение ошибок конфигурации на этапе компиляции;

• Отсутствие необходимости изменять код компонентов;

• Минимальные зависимости на этапах сборки и выполнения;

Общие требования:

• Лицензия допускает коммерческое использование;

• Прохождение апробации в крупных проектах;

• Активное развитие и поддержка проекта;

DI фреймворк: требования AVPSUS

24

[C++98] PocoCapsule[Detector.xml]<?xml version=”1.0”?><!DOCTYPE poco-application-context SYSTEM “http://www.pocomatic.com/poco-application-context.dtd”><poco-application-context>

<load library=“./virus_detector.$dll“/><load library=“./virus_detector_reflx.$dll“/><bean class=“IVirusBases“ factory-

method=“CreateVirusBases“/><beanclass=”VirusDetector”id=”detector”destroy-method=”delete”lazy-init=”false”><method-arg ref=”IVirusBases”/><ioc method=”Init”>

<method-arg type=”cstring” value=”mode=fast”/></ioc>

</bean></poco-application-context>

[Detector.h]struct IVirusBases {};class VirusBases : public IVirusBases {};

IVirusBases* CreateVirusBases(){ return new VirusBases(); }

class VirusDetector {public:

explicit VirusDetector(IVirusBases*);void Init(const char*);void Detect();

};

25

[C++98] PocoCapsule

virus_detector_reflx.dll

virus_

detector.h

virus_

detector.xml

pxgenproxy

virus_

detector.cc

main.exe

main.cpppococapsule.dll

[main.cpp]

#include <pocoapp.h>

int main(int argc, char** argv){

POCO_AppContext* ctxt = POCO_AppContext::create(“virus_detector.xml”, “file”);

VirusDetector* det = ctxt->getBean("detector");det->Detect();

ctxt->terminate();ctxt->destroy();

}

26

[C++03] Wallaroo

[virus_detector.h]

#include "wallaroo/registered.h"

struct IVirusBases : public wallaroo::Part {};

class VirusBases : public IVirusBases {};

class VirusDetector : public wallaroo::Part

{

wallaroo::Collaborator<IVirusBases>

m_virusBases;

public:

VirusDetector(IVirusBases* virusBases);

void Detect();

};

[virus_detector.cpp]

#include "virus_detector.h"

WALLAROO_REGISTER(IVirusBases)

WALLAROO_REGISTER(VirusBases)

WALLAROO_REGISTER(VirusDetector, IVirusBases*)

VirusDetector::VirusDetector()

: m_virusBases("m_virusBases", RegistrationToken())

{}

void VirusDetector::Detect() {}

27

int main(int argc, char* argv[]) {

try {

Catalog catalog;

catalog.Create("virusDetector", "VirusDetector");

catalog.Create("virusBases", "VirusBases");

use(catalog["virusBases"]).as("m_virusBases").of(catalog["virusDetector"]);

shared_ptr<VirusDetector> virusDetector = catalog["virusDetector"];

virusDetector->Detect();

}

catch (const wallaroo::WallarooError& error) {

std::cerr << "ERROR: " << error.what() << std::endl;

}

return 0;

}

[C++03] Wallaroo

28

[C++11] Google Fruitclass IVirusBases {

virtual void Check(string s) = 0;

};

class VirusBases : public IVirusBases {

public:

VirusBases() = default;

virtual void Check() override {

...

}

};

struct IVirusDetector {

virtual void Detect() = 0;

};

class VirusDetector : publicIVirusDetector {

shared_ptr<IVirusBases> m_bases;

public:

VirusDetector(constshared_ptr<IVirusBases>& bases)

: m_bases(bases) {}

virtual void Detect() override {

m_bases->Check();

}

};

29

Component<IVirusDetector> getDetectorComponent()

{

return fruit::createComponent()

.registerConstructor<VirusDetector(IVirusBases*)>()

.registerConstructor<VirusBases()>()

.bind<IVirusBases, VirusBases>()

.bind<IVirusDetector, VirusDetector>();

}

int main() {

Injector<IVirusDetector>

injector(getDetectorComponent());

shared_ptr<IVirusDetector> detector =

injector.get<IVirusDetector*>();

detector->Detect();

return 0;

}

[C++11] Google Fruit

30

[C++03/11/14]Boost.DI

struct IVirusBases {virtual void Check() = 0;

};

class VirusBases : public IVirusBases {…};

struct IAntimalware {virtual void Scan() = 0;

};

class Antimalware : public IAntimalware{...};

class VirusDetector{shared_ptr<IVirusBases> m_virusBases;shared_ptr<IAntimalware> m_antimalware;bool m_value;

public:VirusDetector(const shared_ptr<IVirusBases>& virusBases,const shared_ptr<IAntimalware>& antimalware,bool value)

: m_virusBases(virusBases), m_antimalware(antimalware), m_value(value){ }

int Detect() const {if (m_value) {

m_virusBases->Check();m_antimalware->Scan();

}return 0;

}};31

int main() {auto injector = di::make_injector(

di::bind<IVirusBases, VirusBases>, di::bind<IAntimalware, Antimalware>, di::bind<bool>.to(true)

);return injector.create<VirusDetector>().Detect();

}

[C++03/11/14]Boost.DI

32

PocoCapsule

WallarooGoogle

FruitBoost.DI

manualDI

Простота конфигурирования компонентов

Да Да Да Да Нет

Явность списка зависимостей компонент

Нет Нет Да Нет Да

Обнаружение ошибок конфигурации на этапе компиляции

Нет Нет Да Да Да

Отсутствие необходимости изменять код компонентов

Да Нет Да Да Да

Минимальные зависимости на этапах сборки и выполнения

Нет Да Да Да Да

33

DI фреймворки: сравнение

PocoCapsule

WallarooGoogle

FruitBoost.DI

manualDI

Лицензия допускает коммерческое использование

LGPL Да Да Да Да

Прохождение апробации в крупных проектах

Нет Нет Нет Нет Да

Активное развитие и поддержка проекта

Нет Да Да Да Да

34

DI фреймворки: сравнение

DI в современном C++: выводы

• Dependency Injection предпочтительнее Service Locator для связывания объектов;

• Для C++-проекта с инверсией зависимости на текущий момент предпочтительнее использовать manual DI либо DI-фреймворк собственной разработки для связывания объектов.

35

Ссылки

• http://www.martinfowler.com/articles/injection.html

• http://www.objectmentor.com/resources/articles/dip.pdf

• https://code.google.com/p/pococapsule/

• https://code.google.com/p/wallaroo/

• https://github.com/google/fruit

• https://github.com/krzysztof-jusiak/di

36

top related