Builder Pattern 在 Objective-C 中的使用

  • 常見的 Objective-C 構造器

31度的高溫,啥也別說,來杯奇異果茶

LYFruitTea *fruitTea = [[LYFruitTea alloc] initWith:LYFruitVariety_Kiwi];

喝起來覺得太甜了,好吧,加個甜度控制

LYFruitTea *fruitTea = [[LYFruitTea alloc] initWith:LYFruitVariety_Kiwi andSweetness:30];

30%的甜度剛好,可是還是很熱呀,能不能加冰呢

LYFruitTea *fruitTea = [[LYFruitTea alloc] initWith:LYFruitVariety_Kiwi sweetness:30 andIced:YES];

LYFruitTea 的內(nèi)部實現(xiàn),一般都是其它構造器層層調(diào)用至最后最長參數(shù)設置的那個構造器(重疊調(diào)用構造器):

- (instancetype)initWith:(LYFruitVariety)fruitVariety {
    return [self initWith:fruitVariety andSweetness:10];
}

- (instancetype)initWith:(LYFruitVariety)fruitVariety andSweetness:(NSInteger)sweetness {
    return [self initWith:fruitVariety sweetness:sweetness andIced:NO];
}

- (instancetype)initWith:(LYFruitVariety)fruitVariety sweetness:(NSInteger)sweetness andIced:(BOOL)iced {
    if (self = [super init]) {
        _fruitVariety = fruitVariety;
        _sweetness = sweetness;
        _iced = iced; 
    }
    return self;
}

擴展性不好,有了新的需求,用戶要選擇是否加牛奶,是否加珍珠,那是否就不斷的擴展/新建構造方法呢?

當然也有另外一種方式:

LYFruitTea *fruitTea = [[LYFruitTea alloc] init];
fruitTea.fruitVariety = LYFruitVariety_Kiwi;
fruitTea.sweetness = 30;
fruitTea.iced = YES;

這樣寫可以滿足要求了吧,擴展性不錯捏,?(?????????)?,可是這樣寫很分散,容易丟失屬性設置(特別是后續(xù)增加的必設屬性),使用者也可能不知道新增了屬性,所以兩種屬性都不能夠很靈活的處理需求變更


  • Builder Pattern

記得曾看過一句話:遇到多個構造器參數(shù)時需要考慮用構建器,它將復雜對象的構造與它的表示分開

Builder Pattern 在 JavaScript 中的使用(這里的 Method Chaining 下一篇)

LYFruitTea *fruitTea = new LYFruitTea.builder()
    .setFruitVariety(LYFruitVariety_Kiwi)
    .setSweetness(30)
    .setIced(YES)
    .build();

新需求需要設置新屬性時,在 build() 調(diào)用前添加 setXXX() 即可,同時若有必設屬性,在 build() 里進行檢查并給予??

對應到 Objective-C 中常規(guī)實現(xiàn)是

LYFruitTea *fruitTea = [[[[[[LYFruitTeaBuilder alloc] init] setFruitVariety:LYFruitVariety_Kiwi] setSweetness:30] setIced:YES] build];

這是在玩貪吃蛇嗎?有種被支配的恐懼

嗯,是的還有另外的實現(xiàn)方式:

LYFruitTeaBuilder *fruitTeaBuilder = [[LYFruitTeaBuilder alloc] init];
fruitTeaBuilder.fruitVariety = fruitVariety;
fruitTeaBuilder.sweetness = sweetness;
fruitTeaBuilder.iced = iced;
LYFruitTea *fruitTea = [fruitTeaBuilder build];

到這里是不是發(fā)現(xiàn)跟之前常用的構造器的問題一樣,是不是看不到 Builder Pattern 在 Objective-C 使用的真正意義,那是因為目前只是僅僅將這個模式直接拷貝至 Objective-C 來實現(xiàn),并未適應 Objective-C


  • Builder Pattern 在 Objective-C 的使用

Builder Pattern 適應 Objective-C 的寫法其實并不特別,就是使用 block (Method Chaining 也是使用 block 實現(xiàn)),并在 block 里進行屬性設置等等配置工作

typedef void(^LYFruitTeaBuilderBlock)(LYFruitTeaBuilder *builder);

LYFruitTea *fruitTea = [LYFruitTea ruitVarietyWith:LYFruitVariety_Kiwi
                                               builder:^(LYFruitTeaBuilder *builder) {
                                                   builder.sweetness = 30;
                                                   builder.iced = YES;
    }];

看起來是不是舒服多了,若是有其他需求變更,集中在塊中進行配置,也不會由于疏忽而忘記了build的調(diào)用,這里只需要關注想要的配置,使用者很方便調(diào)用

其中ruitVarietyWith:builder:的方法實現(xiàn)

+ (LYFruitTea *)ruitVarietyWith:(LYFruitVariety)fruitVariety builder:(LYFruitTeaBuilderBlock)block {
    NSParameterAssert(block);
    LYFruitTeaBuilder *builder = [[LYFruitTeaBuilder alloc] initWith:fruitVariety];
    block(builder);
    return [builder build];
}

LYFruitTeaBuilder 的 build 方法實現(xiàn):

- (LYFruitTea *)build {
/*進行一些條件的檢查*/
    LYFruitTea *fruitTea = [[LYFruitTea alloc] initWithBuilder:self];
    return fruitTea;
}

LYFruitTea 的 initWithBuilder: 方法實現(xiàn):

- (instancetype)initWithBuilder:(LYFruitTeaBuilder *)builder {
    if (self = [super init]) {
        _fruitVariety = builder.fruitVariety;
        _sweetness = builder.sweetness;
        _iced = builder.iced;
    }
    return self;
}

當然也可以將這一操作集中在 LYFruitTeaBuilder 一起完成:

- (LYFruitTea *)build {
/*進行一些條件的檢查*/
    LYFruitTea *fruitTea = [[LYFruitTea alloc] init];
    fruitTea.fruitVariety = self.fruitVariety;
    fruitTea.sweetness = self.sweetness;
    fruitTea.iced = self.iced;
    return fruitTea;
}

這兩種進行最后配置時的操作,看個人習慣,怎么方便怎么來,個人更傾向于后面一種,避免了兩個地方的互相調(diào)用,引起的查閱不便,可讀性更強

作為客戶端開發(fā),常常會有需求展示的變更,以便于產(chǎn)品快速進行驗證,這個時候使用 Builder Pattern 最大的好處,就是配置進行統(tǒng)一配置,看起來整潔,需求變更,開發(fā)人員可以快速響應,無需大片改動代碼,非常便于后期人員的理解維護

哎,感覺今天蔫蔫的,先醬紫吧,腦袋一片漿糊呢

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,551評論 19 139
  • 1、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明AI閱讀 16,203評論 3 119
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結構(3).初始化時...
    歐辰_OSR閱讀 30,228評論 8 265
  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學習記錄文檔,今天18年5月份再次想寫文章,發(fā)現(xiàn)簡書還為我保存起的...
    Jenaral閱讀 3,142評論 2 9
  • 挺立沙漠的胡楊 你為啥淚流成行 抗擊干旱 創(chuàng)造荒野奇跡 抵御鹽堿 深深扎根土壤 堅守大漠 頂住風吹沙揚 吸入太多鹽...
    珠江潮平閱讀 300評論 6 11

友情鏈接更多精彩內(nèi)容