码迷,mamicode.com
首页 > 移动开发 > 详细

设计模式之工厂模式(iOS开发,代码用Objective-C展示)

时间:2015-09-08 13:51:02      阅读:336      评论:0      收藏:0      [点我收藏+]

标签:

《大话设计模式》这是一本经典之作,本来我该看《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     }
View Code

这样的代码,结果是不会有错,但是请注意,其中完全是面向过程的思维,而题目中是要你用面向对象语言实现。无疑,上面的代码肯定是不能另面试官满意的,加以修改,有如下代码:

技术分享
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
View Code
技术分享
 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
View Code

为什么一定要采用面向对象的思维?那是因为面向过程的思维,会使得我们的程序只为满足当前需求设计,这样会导致程序不易维护、不易扩展、更不易复用,从而达不到高质量代码的要求。

用书中一个实例来说明:就像曹操赋诗,“喝酒唱歌,人生真爽。......”然后一橙子拍马屁速度命令印刷将刻印。刻印好后,拿给曹操看,曹操觉得太通俗,得改改,于是改成,“对酒当歌,人生真爽。......”然后印刷将在此刻印好之后,给曹操看,曹操觉得还是要改,“对酒当歌,人生几何。......”。印刷将卒。

那个时代,并没有活字印刷术,如果要改字,就得全部重刻,想想,酒、歌、人、生这四个字,结构顺序都不应当改变的,也就是说,如果要重刻,在有活字印刷术的情况下,只需要重刻对、酒、几、何。

面向过程的思维就好比全部重刻,先前其余工作都是白费的,而面向对象的思维,就相当于只改变需要重刻的字,先前其他工作都未白做。

在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
View Code
技术分享
 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
View Code
技术分享
 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
View Code
技术分享
 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
View Code
技术分享
 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
View Code

为何这么说,上面的代码扩展性极好呢?如果,我想要为这个计算类增加一个开根号的操作,那么再生产一个继承自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
View Code

在控制器里面的代码,可以这样写:

技术分享
 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
View Code

这样,一个简单的工厂设计模式便实现了,下面是这几个类的结构图(采用书本原图,类名、方法名、属性名并未完全采用书本上的)

技术分享

一个简单的四则运算,也是可以写出如此精彩、优美的代码,不得不承认,编程不仅仅是一门技术,更是一门艺术。

 

 

设计模式之工厂模式(iOS开发,代码用Objective-C展示)

标签:

原文地址:http://www.cnblogs.com/ziyi--caolu/p/4791356.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!