あのパターンと仲良く付き合う 西磨翁 #yxcm
DESCRIPTION
ヤフー vs クラスメソッド「iOS 炎の7番勝負」にて発表 http://connpass.com/event/5159/ http://dev.classmethod.jp/news/yxcm/ #yxcmTRANSCRIPT
あのパターンと 仲良く付き合うMao Nishitwitter:@mao_nishi
Gang of Four 23種類のパターン
その中でも馴染みが深い パターンといえば
Singleton
+(instancetype)sharedInstance { static UserManager *instance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [[UserManager alloc]init]; }); return instance; }
よくある実装
[UserManager sharedInstance].userName = @"taro";
よくある呼び出し
よく使われている
• [NSUserDefaults standardUserDefaults]
• [NSNotificationCenter defaultCenter]
• [NSBundle mainBundle]
• 他にもいろいろ
開発当初・・
Class A Singleton Class参照
開発が進んでくると・・
Class A
Class B Class C
Singleton Class参照
参照参照 参照
依存性するオブジェクトが増えてくる
Class A
Class BClass C
Singleton Class
Singleton Class
参照
参照参照
参照 参照
単体で利用できない オブジェクトが増えてくる
単体でテストしたいのに
Singleton実装のクラスに
テスト用のコード(reset、clear、フラグ制御等) 入れちゃったり
依存性が高くなることが Singletonパターン
のデメリットとして挙げられる
Singleton パターン(シングルトン・パターン)とは、GoF(Gang of Four; 4人のギャングたち)によって定義されたデザインパターンの1つである。Singleton パターンを用いると、そのクラスのインスタンスが1つしか生成されないことを保証することができる。 ロケールやLook&Feelなど、絶対にアプリケーション全体で統一しなければならな
い仕組みの実装に使用される。 !
wikipedia参照
http://ja.wikipedia.org/wiki/Singleton_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3
Singletonパターンが悪いわけではなく静的に呼び出していることが問題
Singletonでよく云われるデメリット
• オブジェクトに依存関係が発生する
• 単体テストで前テスト状態を引き継いでしまう
• 再利用、継承できない。sharedInstanceで継承元のインスタンスが返却される
デメリットは分かった でも必要な場面がある
デメリットを解消するには?
!
依存性の注入というアプローチ で静的な呼び出しを解消する
依存性の注入(いそんせいのちゅうにゅう、英:
Dependency injection)とは、コンポーネント間の依存関係をプログラムのソースコードから排除し、外部の設定ファイルなどで注入できるようにするソフトウェアパターンである。英語の頭文字からDIと略される。
!
wikipedia参照
http://ja.wikipedia.org/wiki/%E4%BE%9D%E5%AD%98%E6%80%A7%E3%81%AE
%E6%B3%A8%E5%85%A5
依存性の注入の概念はXCodeでも見受けられる
User Defined Runtime Attributes External Object
Singletonに対して注入するIFは見受けられない
Objective-c向けの 依存性の注入フレームワーク
Singletonでよく云われるデメリット
• オブジェクトに依存関係が発生する
• 単体テストで前テスト状態を引き継いでしまう
• 再利用、継承できない。sharedInstanceで継承元のインスタンスが返却される
block構文で注入可能 (xmlファイルでも可)
TyphoonAssembly
注入処理の実装
@implementation MiddleAgesAssembly - (id)userManager { return [TyphoonDefinition withClass: [UserManager class]initialization:^(TyphoonInitializer *initializer) { } properties:^(TyphoonDefinition *definition) { //singletonにしたいとき [definition setScope:TyphoonScopeSingleton]; !! [definition injectProperty:@selector(forTintColor) withValueAsText:@"#0a1d3b"]; [definition injectProperty:@selector(conTintColor) withValueAsText:@"#606970"]; }]; }]; } @end
呼び出しは少々冗長
TyphoonComponentFactory *factory = [[TyphoonBlockComponentFactory alloc] initWithAssembly:[UserManagerAssembly assembly]]; ! UserManager *userManager = [(UserManagerAssembly*)factory userManager];
Singletonでよく云われるデメリット
• オブジェクトに依存関係が発生する
• 単体テストで前テスト状態を引き継いでしまう
• 再利用、継承できない。sharedInstanceで継承元のインスタンスが返却される
DIコンテナ経由のアクセスで Singletonも実現できる
Singleton
参照
not Singleton not Singleton
参照
シングルトン実装されていないクラスなのに シングルトンパターンが適用できる
before after
Class A Class B Class A Class B
Typhoon(DIコンテナ)
テストメソッド毎に オブジェクトを生成できる
特別な初期化処理が不要になる
Singletonでよく云われるデメリット
• オブジェクトに依存関係が発生する
• 単体テストで前テスト状態を引き継いでしまう
• 再利用、継承できない。sharedInstanceで継承元のインスタンスが返却される
継承後の生成処理に余計な処理を作らなくて済む
Singleton A
Class C
sharedInstanceA
Class G
Singleton B
not Singleton E
not Singleton F
sharedInstanceB alloc initalloc init
before after
まとめ• Singletonパターンが悪いのではなく、静的に呼び出しをしていることが悪い状態を招く
• Typhoonを使うことでSingletonの実装を行わなくてもSingletonパターンを実現することができる
• 単体テストコード中でSingletonに対する処置を書く必要がなくなる
!
依存性の注入を利用して Singletonパターンと上手に お付き合いしていきましょう
そして単体テストが楽にできる環境を作っていきましょう!
ご静聴ありがとうございました
引用させて頂いた資料• http://www.typhoonframework.org/#prettyPhoto
• http://ja.wikipedia.org/wiki/Singleton_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3
• http://ja.wikipedia.org/wiki/%E4%BE%9D%E5%AD%98%E6%80%A7%E3%81%AE%E6%B3%A8%E5%85%A5
• http://nikic.github.io/2011/12/27/Dont-be-STUPID-GRASP-SOLID.html
• http://phpmentors.jp/post/58653036033/dont-be-stupid-but-grasp-solid