あのパターンと仲良く付き合う 西磨翁 #yxcm

Preview:

DESCRIPTION

ヤフー vs クラスメソッド「iOS 炎の7番勝負」にて発表 http://connpass.com/event/5159/ http://dev.classmethod.jp/news/yxcm/ #yxcm

Citation preview

あのパターンと 仲良く付き合う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

Recommended