Smirnov dependency-injection-techforum(1)

27

Transcript of Smirnov dependency-injection-techforum(1)

Page 1: Smirnov dependency-injection-techforum(1)
Page 2: Smirnov dependency-injection-techforum(1)

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

[email protected]

@__smirnov__

Page 3: Smirnov dependency-injection-techforum(1)

DEPENDENCY INJECTION

@__smirnov__

Page 4: Smirnov dependency-injection-techforum(1)

EVERY SOLUTION NEEDS A PROBLEM@__smirnov__

Page 5: Smirnov dependency-injection-techforum(1)

ПРОБЛЕМЫ

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

@end

@implementation Emailer

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

@end

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

@__smirnov__

Page 6: Smirnov dependency-injection-techforum(1)

РЕШЕНИЯ ДО DEPENDENCY INJECTION

•Construction by hand

•Factory pattern

•ServiceLocator pattern

@__smirnov__

Page 7: Smirnov dependency-injection-techforum(1)

CONSTRUCTION BY HAND@__smirnov__

Page 8: Smirnov dependency-injection-techforum(1)

CONSTRUCTION BY HAND

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

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

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

- (id)init;

@__smirnov__

Page 9: Smirnov dependency-injection-techforum(1)

FACTORY PATTERN@__smirnov__

Page 10: Smirnov dependency-injection-techforum(1)

FACTORY PATTERN

@interface EmailerFactory{}

- (id<Emailer>) createKlingonEmailer;

@end

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

@__smirnov__

Page 11: Smirnov dependency-injection-techforum(1)

@interface EmailerFactory{}

- (id<Emailer>) createKlingonEmailer;

@end

FACTORY PATTERN

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

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

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

@__smirnov__

Page 12: Smirnov dependency-injection-techforum(1)

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

@__smirnov__

Page 13: Smirnov dependency-injection-techforum(1)

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__

Page 14: Smirnov dependency-injection-techforum(1)

THE HOLLYWOOD PRINCIPLE@__smirnov__

Page 15: Smirnov dependency-injection-techforum(1)

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

@__smirnov__

Page 16: Smirnov dependency-injection-techforum(1)

BIG DI BENEFITS

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

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

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

• !Scopes!

@__smirnov__

Page 17: Smirnov dependency-injection-techforum(1)

INJECTION IDIOMS

•Constructor injection

•Setter injection

•Interface injection

•Field injection

•Method injection (AOP)

NO IMAGE, SORRY

@__smirnov__

Page 18: Smirnov dependency-injection-techforum(1)

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__

Page 19: Smirnov dependency-injection-techforum(1)

SETTER INJECTION

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

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

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

@__smirnov__

Page 20: Smirnov dependency-injection-techforum(1)

METHOD INJECTION (AOP)

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

@__smirnov__

Page 21: Smirnov dependency-injection-techforum(1)

BEYOND THE SCOPE

• Singleton scope

• Transition objects, no scope

GENERAL PURPOSE SCOPES

• Request scope

• Session scope

• ...

APPLICATION LEVEL SCOPES

@__smirnov__

Page 22: Smirnov dependency-injection-techforum(1)

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__

Page 23: Smirnov dependency-injection-techforum(1)

DOMAIN-SPECIFIC SCOPE

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

@__smirnov__

Page 24: Smirnov dependency-injection-techforum(1)

IOS DEPENDENCY INJECTION

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

@__smirnov__

Page 25: Smirnov dependency-injection-techforum(1)

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__

Page 27: Smirnov dependency-injection-techforum(1)

@__smirnov__