标签:
《大话设计模式》这是一本经典之作,本来我该看《Objective-C编程之道:IOS设计模式解析 》,其实我也是先看的《Objective-C编程之道:IOS设计模式解析 》,但不得不说,其中内容有些深奥,理解起来比较困难。这与我一贯的学习方针不合,我更喜欢一个循序渐进的过程,从认知到实践再到思维上的一个比较深入的学习。然后有朋友向我推荐了《大话设计模式》这本书籍,初看,感觉很是符合我现在这个阶段,在此以前,我所编码中接触的设计模式都是比较简单的,在代码上也有体现,但是终究缺少一个系统的、全面的,在思维上的认知与理解。
才看完第一章,就已经很兴奋了,我相信这本书籍对我以后代码设计会有非常大的帮助,在此我打算以自己的理解方式,将其中思维、代码用c\oc翻译一次,以便加深自己对其理解。
例子:
小菜去面试一家公司,有一道面试题是这样的:请用任意一种面向对象语言,实现一个计算器控制台程序,要求输入两个数和运算符号,得到结果。
如果是一年以前,我会很快写出下面的代码(只能说,在大学搞acm,面向过程思维太丰富):
1 double numberA = 0, numberB = 0; 2 3 char operationChar; 4 printf("请输入numberA = "); 5 scanf("%lf",&numberA); 6 printf("请输入+、-、*、/四种运算符中的一种:"); 7 scanf("%c",&operationChar); 8 printf("请输入numberB = "); 9 scanf("%lf",&numberB); 10 11 switch (operationChar) { 12 case ‘+‘: 13 printf("结果是:%2lf\n",numberA + numberB); 14 break; 15 16 case ‘-‘: 17 printf("结果是:%2lf\n",numberA - numberB); 18 break; 19 20 case ‘*‘: 21 printf("结果是:%2lf\n",numberA * numberB); 22 break; 23 24 case ‘/‘: 25 if (numberB == 0) { 26 printf("numberB不能为0\n"); 27 } 28 else{ 29 printf("结果是:%2lf\n",numberA / numberB); 30 } 31 break; 32 33 }
这样的代码,结果是不会有错,但是请注意,其中完全是面向过程的思维,而题目中是要你用面向对象语言实现。无疑,上面的代码肯定是不能另面试官满意的,加以修改,有如下代码:
1 #import <Foundation/Foundation.h> 2 3 @interface ZYCount : NSObject 4 @property (nonatomic, copy) NSString *operationStr; 5 - (instancetype)initWithNumberA:(double)numberA numberB:(double)numberB; 6 @end
1 #import "ZYCount.h" 2 3 @interface ZYCount () 4 @property (nonatomic, assign) double numberA; 5 @property (nonatomic, assign) double numberB; 6 @end 7 8 @implementation ZYCount 9 - (instancetype)initWithNumberA:(double)numberA numberB:(double)numberB 10 { 11 if (self = [super init]) { 12 self.numberA = numberA; 13 self.numberB = numberB; 14 } 15 return self; 16 } 17 18 - (void)setOperationStr:(NSString *)operationStr 19 { 20 _operationStr = [operationStr copy]; 21 22 if ([operationStr isEqualToString:@"+"]) { 23 24 NSLog(@"%.2lf",self.numberA + self.numberB); 25 } 26 else if ([operationStr isEqualToString:@"-"]) { 27 28 NSLog(@"%.2lf",self.numberA - self.numberB); 29 } 30 else if ([operationStr isEqualToString:@"*"]) { 31 NSLog(@"%.2lf",self.numberA * self.numberB); 32 33 } if ([operationStr isEqualToString:@"/"]) { 34 NSLog(@"%.2lf",self.numberA / self.numberB); 35 36 } 37 } 38 @end
为什么一定要采用面向对象的思维?那是因为面向过程的思维,会使得我们的程序只为满足当前需求设计,这样会导致程序不易维护、不易扩展、更不易复用,从而达不到高质量代码的要求。
用书中一个实例来说明:就像曹操赋诗,“喝酒唱歌,人生真爽。......”然后一橙子拍马屁速度命令印刷将刻印。刻印好后,拿给曹操看,曹操觉得太通俗,得改改,于是改成,“对酒当歌,人生真爽。......”然后印刷将在此刻印好之后,给曹操看,曹操觉得还是要改,“对酒当歌,人生几何。......”。印刷将卒。
那个时代,并没有活字印刷术,如果要改字,就得全部重刻,想想,酒、歌、人、生这四个字,结构顺序都不应当改变的,也就是说,如果要重刻,在有活字印刷术的情况下,只需要重刻对、酒、几、何。
面向过程的思维就好比全部重刻,先前其余工作都是白费的,而面向对象的思维,就相当于只改变需要重刻的字,先前其他工作都未白做。
在IT这行业,有太多类似曹操这类客户,动不动就改变需求,在他们看来,只是几个界面的变动,应该很简单,但是如果我们自己,不把相应的模块封装好、把耦合度降低,也许改动起来工作量就是非常大了,但是,如果在编码之初,就有这么一种考虑,并将相应结构划分好,无疑工作量会大大降低。而面向对象以及设计模式,正是许多前辈总结出来的,为解决此问题的方法。
复制与复用
在iOS开发中,每当有几个界面相似度很高时,打开对应文件,总可以看到每个文件内都有一大堆重复的代码。这种现象在iOS开发中,最为常见。(ps:昨天一个一年工作经验的iOS开发者来我公司面试,开口就是16k,然后水平比我还低,喂喂,话说我只是个应届毕业生(今年毕业的),这样真的好么?)不得不说,这一行,水货太多,水也就算了,还TM不懂得在各方面提升自己,想想也是醉了,恩,我自己也是水货~~
其实,解决这类问题是完全可以的,把重复的业务逻辑抽出来到相应的工具类里面,重复的界面逻辑处理抽出来到基类里面,其他界面逻辑类继承自这个基类,把重复的数据处理抽出来到相应的model里面,这样,代码复用度就比较ok了,也摆脱了,command+A , command+C , command+V的怪圈,如果有需要修改的地方,只需要找到对应的类,对应的逻辑改一次,其他相应的所有界面、相应的所有逻辑就都改变了。
如果说,继承与多态在此次设计中要用到,从而使得代码极易扩展,那么就有了如下代码:
1 #import <Foundation/Foundation.h> 2 3 @interface ZYCount : NSObject 4 @property (nonatomic, assign) double numberA; 5 @property (nonatomic, assign) double numberB; 6 - (instancetype)initWithNumberA:(double)numberA numberB:(double)numberB; 7 8 /** 9 * 由于不知道子类的具体运算,所以,这个方法交给子类去实现即可(又由于此方法,所有子类都会有此一次运算,而不是某个子类所特有的,所以放到基类里最合适) 10 * 11 */ 12 - (double)resultForCount; 13 @end 14 15 16 #import "ZYCount.h" 17 18 @interface ZYCount () 19 @end 20 21 @implementation ZYCount 22 - (instancetype)initWithNumberA:(double)numberA numberB:(double)numberB 23 { 24 if (self = [super init]) { 25 _numberA = numberA; 26 _numberB = numberB; 27 } 28 return self; 29 } 30 31 @end
1 #import "ZYCount.h" 2 3 @interface ZYCountAdd : ZYCount 4 @end 5 6 #import "ZYCountAdd.h" 7 8 @implementation ZYCountAdd 9 - (double)resultForCount 10 { 11 return self.numberA + self.numberB; 12 } 13 @end
1 #import "ZYCount.h" 2 3 @interface ZYCountSubtractor : ZYCount 4 5 @end 6 7 #import "ZYCountSubtractor.h" 8 9 @implementation ZYCountSubtractor 10 - (double)resultForCount 11 { 12 return self.numberA - self.numberB; 13 } 14 @end
1 #import "ZYCount.h" 2 3 @interface ZYCountMuli : ZYCount 4 5 @end 6 7 #import "ZYCountMuli.h" 8 9 @implementation ZYCountMuli 10 - (double)resultForCount 11 { 12 return self.numberA * self.numberB; 13 } 14 @end
1 #import "ZYCount.h" 2 3 @interface ZYCountDivision : ZYCount 4 5 @end 6 7 #import "ZYCountDivision.h" 8 9 @implementation ZYCountDivision 10 - (double)resultForCount 11 { 12 if (self.numberB == 0) { 13 NSLog(@"除数为0,产出错误"); 14 return 0; 15 } 16 return self.numberA / self.numberB; 17 } 18 @end
为何这么说,上面的代码扩展性极好呢?如果,我想要为这个计算类增加一个开根号的操作,那么再生产一个继承自ZYCount的子类,在- (double)
resultForCount方法里面实现开根号操作,完全不必去改动其他任何类。
这样写,还是有问题的。在iOS开发时,我们总不应该将业务逻辑代码放到View\ViewController模块里面,如此,延伸出一个解决这样问题的工具类。对于上面的代码,我们已经使它扩展性、可复用性足够好了,也进行了足够的封装,但是基于业务逻辑与界面逻辑分离的要求,我们可以使用工厂模式,来实现这样的分离,代码如下:
1 #import <Foundation/Foundation.h> 2 3 @class ZYCount; 4 5 @interface ZYCountTool : NSObject 6 + (ZYCount *)creatCountForOperation:(NSString *)operationStr; 7 @end 8 9 10 #import "ZYCountTool.h" 11 #import "ZYCountAdd.h" 12 #import "ZYCountSubtractor.h" 13 #import "ZYCountMuli.h" 14 #import "ZYCountDivision.h" 15 @implementation ZYCountTool 16 + (ZYCount *)creatCountForOperation:(NSString *)operationStr 17 { 18 if ([operationStr isEqualToString:@"+"]) { 19 return [[ZYCountAdd alloc] init]; 20 } 21 else if ([operationStr isEqualToString:@"-"]) { 22 return [[ZYCountSubtractor alloc] init]; 23 } 24 else if ([operationStr isEqualToString:@"*"]) { 25 return [[ZYCountMuli alloc] init]; 26 } 27 28 return [[ZYCountDivision alloc] init]; 29 } 30 @end
在控制器里面的代码,可以这样写:
1 #import "ViewController.h" 2 #import "ZYCountAdd.h" 3 #import "ZYCountTool.h" 4 @interface ViewController () 5 6 @end 7 8 @implementation ViewController 9 10 - (void)viewDidLoad { 11 [super viewDidLoad]; 12 // Do any additional setup after loading the view, typically from a nib. 13 14 ZYCountAdd *p = (ZYCountAdd *)[ZYCountTool creatCountForOperation:@"+"]; 15 p.numberA = 10; 16 p.numberB = 20; 17 NSLog(@"%lf",[p resultForCount]); 18 } 19 20 @end
这样,一个简单的工厂设计模式便实现了,下面是这几个类的结构图(采用书本原图,类名、方法名、属性名并未完全采用书本上的)
一个简单的四则运算,也是可以写出如此精彩、优美的代码,不得不承认,编程不仅仅是一门技术,更是一门艺术。
设计模式之工厂模式(iOS开发,代码用Objective-C展示)
标签:
原文地址:http://www.cnblogs.com/ziyi--caolu/p/4791356.html