smirnov dependency-injection-techforum(1)

Post on 22-Jun-2015

523 Views

Category:

Documents

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Александр СмирновРуководитель группы разработки, iOS Почта

alex.smirnov@corp.mail.ru

@__smirnov__

DEPENDENCY INJECTION

@__smirnov__

EVERY SOLUTION NEEDS A PROBLEM@__smirnov__

ПРОБЛЕМЫ

@interface Emailer : NSObject { @private KlingonSpellChecker* spellChecker;}

@end

@implementation Emailer

- (id)init { if(self = [super init]) spellChecker = [KlingonSpellChecker new]; return self;}

@end

• Связанный код• Сложно переиспользовать• Не тестируемый• Зависимости скрыты

@__smirnov__

РЕШЕНИЯ ДО DEPENDENCY INJECTION

•Construction by hand

•Factory pattern

•ServiceLocator pattern

@__smirnov__

CONSTRUCTION BY HAND@__smirnov__

CONSTRUCTION BY HAND

- (id)initWithSpellChecker:(id<SpellChecker>) spellChecker;

• Нет сокрытия зависимостей • “Тестируемо”

• Инъекция ‘руками’, нет возможности сменить все и сразу • Клиенты сервисов должны знать как связаны графы объектов

- (id)init;

@__smirnov__

FACTORY PATTERN@__smirnov__

FACTORY PATTERN

@interface EmailerFactory{}

- (id<Emailer>) createKlingonEmailer;

@end

+- (id)initWithSpellChecker:(id<SpellChecker>) spellChecker;

@__smirnov__

@interface EmailerFactory{}

- (id<Emailer>) createKlingonEmailer;

@end

FACTORY PATTERN

• Нет сокрытия зависимостей• “Тестируемо”• Есть способ сменить все зависимости разом

• Сами создаем объекты • Больше сложных зависимостей это более сложные фабрики

• Меняем код, чтобы тестировать • По фабрике на каждый сервис ?

@__smirnov__

SERVICE LOCATOR PATTERN[serviceLocator resolveByProtocol: @protocol(Emailer)];[serviceLocator resolveByName: @"KlingonEmailer"];

@__smirnov__

SERVICE LOCATOR PATTERNThe key difference is that with a Service Locator every user of a

service has a dependency to the locator. The locator can hide dependencies to other implementations, but you do need to see

the locator. (c) Martin Fowler

So the decision between locator and injector depends on whether that dependency is a problem.

@__smirnov__

THE HOLLYWOOD PRINCIPLE@__smirnov__

THE HOLLYWOOD PRINCIPLEDon’t call us; we’ll call you

@__smirnov__

BIG DI BENEFITS

•Тестируемый код

•Переиспользуемый код

•Слабо связанный код

• !Scopes!

@__smirnov__

INJECTION IDIOMS

•Constructor injection

•Setter injection

•Interface injection

•Field injection

•Method injection (AOP)

NO IMAGE, SORRY

@__smirnov__

CONSTRUCTOR INJECTIONПолностью готовый к работе объект

@interface SMTPEmailer<Emailer>- (instancetype) initWithSpellchecker:(id<Spellchecker>) spellchecker addressbook:(id<AddressBook>) addressbook;@end

@interface EmailerClient: NSObject- (instancetype) initWithEmailer:(id<Emailer>) emailer;@end

@__smirnov__

SETTER INJECTION

@interface SMTPEmailer<Emailer>@property(nonatomic, strong) id <Spellchecker> spellchecker;@property(nonatomic, strong) id <AddressBook> addressbook;@end

Можем модифицировать зависимостиМожем получить полусобранный объект

Можем намеренно не предоставлять часть зависимостей

@__smirnov__

METHOD INJECTION (AOP)

- (void) sendLetterWithSubject:(NSString*) subject text:(NSString*) text { NSLog(@"enter sendLetterWithSubject"); // do some real work NSLog(@"exit sendLetterWithSubject");}

@__smirnov__

BEYOND THE SCOPE

• Singleton scope

• Transition objects, no scope

GENERAL PURPOSE SCOPES

• Request scope

• Session scope

• ...

APPLICATION LEVEL SCOPES

@__smirnov__

SINGLETON SCOPE- (id) init { return self = [super init];}- (void) doSomeWork { [[Emailer sharedInstance] sendEmail];}

- (id) initWithEmailer:(id<Emailer>) emailer { if(self = [super init]) _emailer = emailer; return self;}- (void) doSomeWork { [_emailer sendEmail];}

@__smirnov__

DOMAIN-SPECIFIC SCOPE

@interface SMTPEmailer<Emailer>- (instancetype) initWithAccount:(Account*) account;@end

@__smirnov__

IOS DEPENDENCY INJECTION

Мыши плакали, кололись, но все равно продолжали есть кактус

@__smirnov__

ALWAYS ALMOST GUICE

•“Annotation” Based Dependency Injection

•Custom Object Providers•Protocol Bindings•Instance Bindings•Lazily instantiates dependencies

Objection or Typhoon

•All above (except “annotation”)+•!Autowiring!•Assembling with blocks or XML•AppCode integration

@__smirnov__

@__smirnov__

top related