偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

8次嘗試,帶你走進(jìn)iOS 精益編程

移動(dòng)開(kāi)發(fā) iOS
Copy-Paste是大部分程序員最容易犯的毛病,為此引入了大量的重復(fù)代碼。

[[153315]]

開(kāi)場(chǎng)

今天, 我們將從一個(gè)小功能開(kāi)始, 先去不假思索的實(shí)現(xiàn)它

Product Repository: Filtering Operation

Code start

有一個(gè)產(chǎn)品庫(kù), 我們要對(duì)它做過(guò)濾操作.

***個(gè)需求并不復(fù)雜.

需求1:在倉(cāng)庫(kù)中查找所有顏色為紅色的產(chǎn)品

First Attempt: Hard Code

我們先用最簡(jiǎn)單的方式去實(shí)現(xiàn)它, 硬編碼

  1. - (NSArray *)findAllRedProducts:(NSArray *)products 
  2. NSMutableArray *list = [@[] mutableCopy]; 
  3. for (Product *product in products) { 
  4. if (product.color == RED) { 
  5. [list addObject:product]; 
  6. return list; 

 

如果這個(gè)世界是永恒靜止的,這樣的實(shí)現(xiàn)無(wú)可厚非,但世界往往并非如此。

緊接著,第二個(gè)需求來(lái)了

需求2:在倉(cāng)庫(kù)中查找所有顏色為綠色的產(chǎn)品

Second Attempt: Parameterizing

Copy-Paste是大部分程序員最容易犯的毛病,為此引入了大量的重復(fù)代碼。

  1. - (NSArray *)findAllGreenProducts:(NSArray *)products 
  2. NSMutableArray *list = [@[] mutableCopy]; 
  3. for (Product *product in products) { 
  4. if (product.color == GREEN) { 
  5. [list addObject:product]; 
  6. return list; 

為了消滅硬編碼,得到可重用的代碼,可以引入簡(jiǎn)單的參數(shù)化設(shè)計(jì)。

  1. - (NSArray *)findProducts:(NSArray *)products byColor:(ProductColor)color 
  2. NSMutableArray *list = [@[] mutableCopy]; 
  3. for (Product *product in products) { 
  4. if (product.color == color) { 
  5. [list addObject:product]; 
  6. return list; 

終于可以放心了, 這個(gè)時(shí)候我們的產(chǎn)品經(jīng)理怎么可能讓你舒服呢,需求3又來(lái)了

需求3:查找所有重量小于10的所有產(chǎn)品

Third Attempt: Parameterizing with Every Attribute You Can Think Of

大部分程序員依然會(huì)使用Copy-Paste解決這個(gè)問(wèn)題,拒絕Copy-Paste的陋習(xí),***實(shí)效的一個(gè)反饋就是讓這個(gè)快捷鍵失效,從而在每次嘗試Copy-Paste時(shí)提醒自己做更好的設(shè)計(jì)

  1. - (NSArray *)findProducts:(NSArray *)products byWeith:(float)weight 
  2. NSMutableArray *list = [@[] mutableCopy]; 
  3. for (Product *product in products) { 
  4. if (product.weight < weight) { 
  5. [list addObject:product]; 
  6. return list; 

為了消除兩者重復(fù)的代碼,通過(guò)簡(jiǎn)單的參數(shù)化往往不能***解決這類問(wèn)題,相反地會(huì)引入過(guò)度的復(fù)雜度和偶發(fā)成本。

  1. - (NSArray *)findProducts:(NSArray *)products byColor:(ProductColor)color byWeith:(float)weight type:(int)type 
  2. NSMutableArray *list = [@[] mutableCopy]; 
  3. for (Product *product in products) { 
  4. if ((type == 1) && product.color == color) { 
  5. [list addObject:product]; 
  6. continue
  7. else if ((type == 2) && (product.weight < weight)) 
  8. [list addObject:product]; 
  9. continue
  10. return list; 

日常工作中,這樣的實(shí)現(xiàn)手法非常普遍,函數(shù)的參數(shù)列表隨著需求增加不斷增加,函數(shù)邏輯承擔(dān)的職責(zé)越來(lái)越多,邏輯也變得越來(lái)越難以控制。

通過(guò)參數(shù)配置應(yīng)對(duì)變化的設(shè)計(jì)往往都是失敗的設(shè)計(jì)

易于導(dǎo)致復(fù)雜的邏輯控制,引發(fā)額外的偶發(fā)復(fù)雜度

Forth Attempt: Abstracting over Criteria

為此需要抽象,使其遍歷的算法與查找的標(biāo)準(zhǔn)能夠獨(dú)立地變化,互不影響。

  1. @interface ProductSpec : NSObject 
  2. - (BOOL)satisfy:(Product *)product; 
  3. @end 

此刻filter的算法邏輯得到封閉,當(dāng)然函數(shù)名需要重命名,使其算法實(shí)現(xiàn)更加具有普遍性。

  1. - (NSArray *)findProducts:(NSArray *)products bySpec:(ProductSpec *)spec 
  2. NSMutableArray *list = [@[] mutableCopy]; 
  3. for (Product *product in products) { 
  4. if ([spec satisfy:product]) { 
  5. [list addObject:product]; 
  6. return list; 

通過(guò)可復(fù)用的類來(lái)封裝各種變化,讓變化的因素控制在最小的范圍內(nèi)。

  1. @interface ColorSpec() 
  2. @property (nonatomic, assign) ProductColor color; 
  3. @end 
  4. @implementation ColorSpec 
  5. + (instancetype)specWithColor:(ProductColor)color 
  6. ColorSpec *spec = [[ColorSpec alloc] init]; 
  7. spec.color = color; 
  8. return spec; 
  9. - (BOOL)satisfy:(Product *)product 
  10. return product.color == RED; 
  11. @end 
  12. @interface BelowWeightSpec() 
  13. @property (nonatomic, assign) float limit; 
  14. @end 
  15. @implementation BelowWeightSpec 
  16. + (instancetype)specWithBelowWeight:(float)limit 
  17. BelowWeightSpec *spec = [[BelowWeightSpec alloc] init]; 
  18. spec.limit = limit; 
  19. return spec; 
  20. - (BOOL)satisfy:(Product *)product 
  21. return (product.weight < _limit); 
  22. @end 

用戶的接口也變得簡(jiǎn)單多了,而且富有表現(xiàn)力。

  1. [self findProducts:_products bySpec:[ColorSpec specWithColor:RED]]; 

這是經(jīng)典的OO設(shè)計(jì),如果熟悉設(shè)計(jì)模式的讀者對(duì)此已經(jīng)習(xí)以為常了。設(shè)計(jì)模式是好東西,但往往被濫用。為此不能依葫蘆畫瓢,死板照抄,而是為了得到更簡(jiǎn)單的設(shè)計(jì)而引入設(shè)計(jì)模式的,這個(gè)過(guò)程是很自然的。

與大師們交流,問(wèn)究此處為何引入設(shè)計(jì)模式,得到的答案:直覺(jué)。忘記所有設(shè)計(jì)模式吧,管它是不是模式,如果設(shè)計(jì)是簡(jiǎn)單的,這就是模式。

另外還有一個(gè)明顯的壞味道,ColorSpec和BelowWeightSpec都需要繼承ProductSpec,都需要定義一個(gè)構(gòu)造函數(shù)和一個(gè)私有的字段,并重寫satisfy方法,這些都充斥著重復(fù)的結(jié)構(gòu)。

是不是覺(jué)得目前的寫法已經(jīng)夠用了? 莫急, 讓我們來(lái)看看下個(gè)需求

需求4:查找所有顏色為紅色,并且重量小于10的所有產(chǎn)品

 

  1. Firth Attempt: Composite Criteria 
  2.  
  3. 按照既有的代碼結(jié)構(gòu),往往易于設(shè)計(jì)出類似ColorAndBelowWeightSpec的實(shí)現(xiàn)。 
  4. @interface ColorAndBelowWeigthSpec() 
  5. @property (nonatomic, assign) ProductColor color; 
  6. @property (nonatomic, assign) float limit; 
  7. @end 
  8. @implementation ColorAndBelowWeigthSpec 
  9. + (instancetype)specWithColor:(ProductColor)color beloWeigth:(float)limit 
  10. ColorAndBelowWeigthSpec *spec = [[ColorAndBelowWeigthSpec alloc] init]; 
  11. spec.color = color; 
  12. spec.limit = limit; 
  13. return spec; 
  14. - (BOOL)satisfy:(Product *)product 
  15. return product.color == _color || (product.weight < _limit); 
  16. @end 

 

存在兩個(gè)明顯的壞味道:

包含and的命名往往是違背單一職責(zé)的信號(hào)燈

ColorAndBelowWeightSpec的實(shí)現(xiàn)與ColorSpec,BelowWeightSpec之間存在明顯的重復(fù)

此刻,需要尋找更本質(zhì)的抽象來(lái)表達(dá)設(shè)計(jì),and/or/not語(yǔ)義可以***解決這類問(wèn)題。

Composite Spec: AndSpec, OrSpec, NotSpec

Atomic Spec:ColorSpec, BeblowWeightSpec

  1. @interface AndSpec() 
  2. @property (nonatomic, strong) NSArray *specs; 
  3. @end 
  4. @implementation AndSpec 
  5. + (instancetype)spec:(ProductSpec *)spec, ... NS_REQUIRES_NIL_TERMINATION 
  6. va_list args; 
  7. va_start( args, spec ); 
  8. NSMutableArray *mArray = [@[spec] mutableCopy]; 
  9. for ( ;; ) 
  10. id tempSpec = va_arg( args, id ); 
  11. if (tempSpec == nil) 
  12. break
  13. [mArray addObject:tempSpec]; 
  14. va_end( args ); 
  15. AndSpec *andSpec = [[AndSpec alloc] init]; 
  16. andSpec.specs = [mArray copy]; 
  17. return andSpec; 
  18. - (BOOL)satisfy:(Product *)product 
  19. for (ProductSpec *spec in _specs) { 
  20. if (![spec satisfy:product]) { 
  21. return NO; 
  22. return YES; 
  23. @end 
  24. @interface OrSpec () 
  25. @property (nonatomic, strong) NSArray *specs; 
  26. @end 
  27. @implementation OrSpec 
  28. + (instancetype)spec:(ProductSpec *)spec, ... NS_REQUIRES_NIL_TERMINATION 
  29. va_list args; 
  30. va_start( args, spec ); 
  31. NSMutableArray *mArray = [@[spec] mutableCopy]; 
  32. for ( ;; ) 
  33. id tempSpec = va_arg( args, id ); 
  34. if (tempSpec == nil) 
  35. break
  36. [mArray addObject:tempSpec]; 
  37. va_end( args ); 
  38. OrSpec *orSpec = [[OrSpec alloc] init]; 
  39. orSpec.specs = [mArray copy]; 
  40. return orSpec; 
  41. - (BOOL)satisfy:(Product *)product 
  42. for (ProductSpec *spec in _specs) { 
  43. if ([spec satisfy:product]) { 
  44. return YES; 
  45. return NO; 
  46. @end 
  47. @interface NotSpec () 
  48. @property (nonatomic, strong) ProductSpec *spec; 
  49. @end 
  50. @implementation NotSpec 
  51. + (instancetype)spec:(ProductSpec *)spec 
  52. NotSpec *notSpec = [[NotSpec alloc] init]; 
  53. notSpec.spec = spec; 
  54. return notSpec; 
  55. - (BOOL)satisfy:(Product *)product 
  56. if (![_spec satisfy:product]) { 
  57. return YES; 
  58. return NO; 
  59. @end 

可以通過(guò)AndSpec組合ColorSpec, BelowWeightSpec來(lái)實(shí)現(xiàn)需求,簡(jiǎn)單漂亮,并且富有表達(dá)力。

  1. [self findProducts:_products bySpec:[AndSpec spec:[ColorSpec specWithColor:RED], [BelowWeightSpec specWithBelowWeight:10], nil]]; 

但這樣的設(shè)計(jì)存在兩個(gè)嚴(yán)重的壞問(wèn)道:

AndSpec與OrSpec存在明顯的代碼重復(fù),OO設(shè)計(jì)的***個(gè)直覺(jué)就是通過(guò)抽取基類來(lái)消除重復(fù)。

  1. @interface CombinableSpec () 
  2. @property (nonatomic, strong) NSArray *specs; 
  3. @end 
  4. @implementation CombinableSpec 
  5. + (instancetype)spec:(CombinableSpec *)spec, ... NS_REQUIRES_NIL_TERMINATION 
  6. va_list args; 
  7. va_start( args, spec ); 
  8. NSMutableArray *mArray = [@[spec] mutableCopy]; 
  9. for ( ;; ) 
  10. id tempSpec = va_arg( args, id ); 
  11. if (tempSpec == nil) 
  12. break
  13. [mArray addObject:tempSpec]; 
  14. va_end( args ); 
  15. CombinableSpec *combinableSpec = [[CombinableSpec alloc] init]; 
  16. combinableSpec.specs = [mArray copy]; 
  17. return combinableSpec; 
  18. - (BOOL)satisfy:(Product *)product 
  19. for (ProductSpec *spec in _specs) { 
  20. if ([spec satisfy:product] == _shortcut) { 
  21. return _shortcut; 
  22. return !_shortcut; 
  23. @end 
  24. @implementation AndSpec 
  25. - (instancetype)init 
  26. self = [super init]; 
  27. if (self) { 
  28. self.shortcut = NO; 
  29. return self; 
  30. @end 
  31. @implementation OrSpec 
  32. - (instancetype)init 
  33. self = [super init]; 
  34. if (self) { 
  35. self.shortcut = YES; 
  36. return self; 
  37. @end 

大堆的初始化方法讓人眼花繚亂

  1. [self findProducts:_products bySpec:[NotSpec spec:[AndSpec spec:[ColorSpec specWithColor:RED], [BelowWeightSpec specWithBelowWeight:10], nil]]]; 
  2.  
  3. Sixth Attempt: Using DSL 

 

可以引入DSL改善程序的可讀性,讓代碼更具表達(dá)力。

我們先添加一些DSL:

  1. static ProductSpec *COLOR(ProductColor color) 
  2. return [ColorSpec specWithColor:RED]; 
  3. static ProductSpec *BELOWWEIGHT(float limit) 
  4. return [BelowWeightSpec specWithBelowWeight:limit]; 
  5. static ProductSpec *AND(ProductSpec *spec1, ProductSpec *spec2) 
  6. return [AndSpec spec:spec1, spec2, nil]; 
  7. static ProductSpec *OR(ProductSpec *spec1, ProductSpec *spec2) 
  8. return [OrSpec spec:spec1, spec2, nil]; 
  9. static ProductSpec *NOT(ProductSpec *spec) 
  10. return [NotSpec spec:spec]; 

這樣我們的代碼表現(xiàn)起來(lái)就是這樣的

  1. [self findProducts:_products bySpec:NOT(AND(COLOR(RED), BELOWWEIGHT(10)))]; 
  2.  
  3. Seventh Attempt: Using a Lambda Expression 

 

可以使用Block改善設(shè)計(jì),增強(qiáng)表達(dá)力。

  1. - (NSArray *)findProducts:(NSArray *)products byBlock:(BOOL (^)())block 
  2. NSMutableArray *list = [@[] mutableCopy]; 
  3. for (Product *product in products) { 
  4. if (block(product)) { 
  5. [list addObject:product]; 
  6. return list; 

代碼現(xiàn)在開(kāi)起來(lái)是這個(gè)樣子

  1. [self findProducts:_products byBlock:^BOOL(id p) {return [p color] == RED;}]; 

構(gòu)造DSL,復(fù)用這些Block

  1. ProductSpecBlock color(ProductColor color) 
  2. return ^BOOL(id p) {return [p color] == color;}; 
  3. ProductSpecBlock weightBelow(float limit) 
  4. return ^BOOL(id p) {return [p weight] < limit;}; 
  5. - (void)test7_2 
  6. [self findProducts:_products byBlock:color(RED)]; 
  7.  
  8. Eighth attempt: Using NSPredicate 

 

還可以使用標(biāo)準(zhǔn)庫(kù)
 

  1. [self.products filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"weight > 10"]]; 

結(jié)束

今天的編碼就到此為止了, 這篇文章本是Horance所寫, 筆者將用OC實(shí)現(xiàn)了一遍.如果咱們不是iOS Developer的話, 還是有其他attempt的, 如泛型.

責(zé)任編輯:chenqingxiang 來(lái)源: 曉月的專欄
相關(guān)推薦

2017-05-16 15:27:32

精益敏捷代碼

2010-03-16 17:30:14

Java多線程編程

2016-07-18 16:09:40

精益生產(chǎn)Testin質(zhì)量控制

2016-02-24 16:09:24

并行科技軟件交付

2009-12-09 13:41:50

PHP Zend框架

2013-08-14 13:35:32

設(shè)計(jì)

2017-09-21 10:34:38

留存分析數(shù)據(jù)分析留存

2011-10-08 14:38:21

精益掃描儀

2011-10-06 17:10:24

精益掃描儀

2010-09-14 10:15:24

2020-07-03 09:41:20

華為∑co時(shí)間醫(yī)療

2011-03-16 14:20:30

2020-08-11 09:47:30

JS閉包代碼

2015-07-22 10:25:09

NEC

2011-07-27 17:05:59

精益掃描儀

2012-06-04 15:26:29

精益掃描儀

2014-03-27 17:20:02

金蝶

2011-09-14 17:21:28

精益掃描儀

2015-11-03 11:08:01

IT高性能運(yùn)維

2023-10-26 01:15:09

得物視頻優(yōu)化
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)