Builder Pattern 在 Objective-C 中的使用
在說 Builder Pattern 之前,我們先來看看一個場景。假設我們要預定一個 iPhone 6,要 64G 的,金色的,用代碼表述大概是這樣
// PFX 是一個前綴,因為直接寫 iPhone6 不符合類名大寫的習慣,寫成 IPhone6 更是怪異 ╮(╯▽╰)╭ PFXiPhone6 *iphone = [[PFXiPhone6 alloc] init]; iphone.storage = 64; iphone.color = [UIColor goldenColor];也可以是另一種方式
PFXiPhone6 *iPhone = [[PFXiPhone6 alloc] initWithStorage:64 color:[UIColor goldenColor]];第一種方式可擴展性好些,但無法約束必須設置某些 property。第二種方式修正了這個問題,但擴展性也差了。
假如又有了新需求,要讓客戶可以選擇發(fā)售區(qū)域,比如港行,國行,美版等等。對于第一種,自然可以新增一個屬性,但使用者很可能完全不知道新增了這么個屬性。對于第二種,則只能再新建一個初始化方式,如?-[initWithStorage:color:place]。那如果又有新的需求,比如選擇是否刻字,以及刻哪些字呢?或者可以選擇外殼的種類等等。這兩種方式都不能很好地處理需求的變更。
現在我們來說說 Builder Pattern,這個模式可以在各種語言里被很方便地實現,比如 javascript
new PFXiPhone6Builder().setStorage(64).setColor('golden').setPlace('HK').build();當有新的屬性時,再加一個?setProperty?即可。如果漏寫了某個屬性,可以在?build?里檢查。
在 Objective-C 里,這樣的鏈式寫法不是很流行(Masonry里這種寫法用的比較多),所以,在 OC 里寫起來大概會是這樣
PFXiPhone6Builder *builder = [[PFXiPhone6Builder alloc] init]; builder.storage = 64; builder.color = [UIColor goldenColor]; builder.place = @"HK"; PFXiPhone6 *iphone = [builder build];如果少了什么屬性,在?build?時檢查下即可。這樣既解決了不方便擴展的問題,當有新的屬性時也可以知道。
不過看起來還是不夠優(yōu)雅,這個 builder 只是一個臨時工具,用完了就扔掉了,既然這樣,那有沒有可能寫法上符合 OC 的傳統(tǒng),又讓這個 builder 「臨時出現」一下?且看下面這段代碼
PFXiPhone6 *iPhone6 = [PFXiPhone6 createWithBuilder:^(PFXiPhone6Builder *builder){builder.storage = 64;builder.color = [UIColor goldenColor];builder.place = @"HK"; }];是不是看起來舒服多了。builder 只是在 block 范圍內起作用,不會影響當前 context 的變量。這個?+[createWithBuilder:]?的代碼如下
+ (instancetype)createWithBuilder:(BuilderBlock)block {NSParameterAssert(block);PFXiPhone6Builder *builder = [[PFXiPhone6Builder alloc] init];block(builder);return [builder build]; }這里?build?方法,也有兩種實現,第一種
// PFXiPhone6Builder - (PFXiPhone6 *)build {return [[PFXiPhone6 alloc] initwithBuilder:self]; }// PFXiPhone6 - (instancetype)initwithBuilder:(PFXiPhone6Builder *)builder {if (self = [super init]) {_storage = builder.storage;_color = builder.color;_place = builder.place;} }另外一種是把兩個過程合并為一個過程
// PFXiPhone6Builder - (PFXiPhone6 *)build {// 可以在這里對 property 做檢查NSAssert(self.place, @"發(fā)行區(qū)別忘了填哦");PFXiPhone6 *iphone6 = [[PFXiPhone6 alloc] init];iPhone6.storage = self.storage;iPhone6.color = self.color;iPhone6.place = self.place;return iPhone6; }這兩種方式的區(qū)別在于對參數的處理,前一個是在目標 Class 中處理,后一種是在 Builder 中處理。
在 Facebook 的?pop?中也有類似的使用,如
POPAnimatableProperty *animatableProperty = [POPAnimatableProperty propertyWithName:@"property" initializer:^(POPMutableAnimatableProperty *prop) {prop.writeBlock = ^(id obj, const CGFloat values[]) {};prop.readBlock = ^(id obj, CGFloat values[]) {}; }];這里的?initializer?其實就是?builder
我在寫蘑菇街的基礎框架時,也有用到過幾處,覺得還是蠻方便的,尤其對使用者來說。比如這個可以橫向或縱向滾動的包含可點擊 Items 的 collectionView。
self.collectionView = [MGJFlowCollectionView collectionViewWithBuilder:^(MGJFlowCollectionViewBuilder *builder) {builder.scrollDirection = UICollectionViewScrollDirectionHorizontal;builder.minimumInteritemSpacing = 10;builder.minimumLineSpacing = 10;builder.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);CGSize itemSize = CGSizeMake(81, 100);builder.itemSize = itemSize;builder.dataSource = @[@1,@2,@3,@4,@5,@6, @7,@8, @9, @10];builder.cellBuilder = ^UIView *(NSNumber *number){UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, itemSize.width, itemSize.height)];view.backgroundColor = [UIColor mgj_random];return view;}; }];這樣就能通過簡單的配置來生成一個水平的或垂直的 collectionView 了。
使用 Builder Pattern 還有一個好處,就是可以將零散的配置統(tǒng)一起來。比如要創(chuàng)建一個 CollectionView,我們需要設置 layout,還要設置 layout 的一些屬性,還要設置 DataSource / Delegate 等,現在可以在一個地方統(tǒng)一設置,可讀性上也會好一些。
所以如果遇到需要多個參數,甚至某個參數自己還包含了各種參數時,可以考慮下 Builder Pattern。
轉載于:https://www.cnblogs.com/wwm881101/p/5460826.html
總結
以上是生活随笔為你收集整理的Builder Pattern 在 Objective-C 中的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL复习(w3school)笔记
- 下一篇: node+express学习日记