Smirnov dependency-injection-techforum(1)
-
Upload
kuchinskaya -
Category
Documents
-
view
511 -
download
1
Transcript of Smirnov dependency-injection-techforum(1)
Александр СмирновРуководитель группы разработки, iOS Почта
@__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__
MATERIALS USED
• Inversion of Control Containers and the Dependency Injection pattern by Martin Fowler
• Dependency Injection by Dhanji R. Prasanna ( author of Guice )• Design Patterns: Dependency Injection by Griffin Caprio ( MSDN Magazine, September 2005 )
• Big Modular Java with Guice ( Google I/O 2009 )• Dependency Injection ( !Wikipedia! )
@__smirnov__
@__smirnov__