文档章节

iOS设计模式(代码分析系列2:简单工厂模式)

召唤攻城狮
 召唤攻城狮
发布于 2014/09/09 21:12
字数 1752
阅读 5.6K
收藏 10

「深度学习福利」大神带你进阶工程师,立即查看>>>

简单工厂模式示例代码下载地址

1、简述

首先需要说明一下,简单工厂模式不属于23种GOF设计模式之一。它也称作静态工作方法模式,是工厂方法模式的特殊实现(也就是说工厂模式包含简单工厂模式)。这里对简单工厂模式进行介绍,是为后面的工厂方法和抽象工厂模式做一个引子。

2、定义

“专门定义一个类来负责创建其他类的实例,被创建的实例通常具有共同的父类。”

世界上就是由一个工厂类,根据传入的参数,动态地决定创建出哪一个产品类的实例。

3、结构图

简要分析结构图:

ConcreteProduct1和ConcreteProduct2两个产品具有一个共同的父类IProject,简单工厂类为SimpleFactory,负责根据传入的不同参数来决定生产ConcreteProduct1还是ConcreteProduct2产品。

4、代码示例讲解

模拟一个使用计算器的场景:用户可以输入两个数和操作符号,然后得到结果,使用交互如下图所示,分别进行除运算减运算

(1)除运算示例

(2)减运算示例

一个新手,极有可能按照自己的初步思维逻辑,判断用户输入的运算符,然后将两个数字进行运算,当然还会加上必要的除数不为0的判断,那么点击运算Button,对应的事件可以如下面这样编写,

- (IBAction)getResult:(id)sender {
    //得到三个文本输入框的内容
    NSString* strFirstNum = self.FirstNumTextField.text;
    NSString* strSecondNum = self.SecondNumTextField.text;
    NSString* strOperation = self.OperationTextField.text;
    //进行运算操作
    if ([strOperation isEqualToString:@"+"]) {
        NSLog(@"+");
        double result = [strFirstNum doubleValue]+[strSecondNum doubleValue];
        self.ResultTextField.text = [NSString stringWithFormat:@"%f",result];
    }else if([strOperation isEqualToString:@"-"]){
        NSLog(@"-");
        double result = [strFirstNum doubleValue]-[strSecondNum doubleValue];
        self.ResultTextField.text = [NSString stringWithFormat:@"%f",result];
    }else if([strOperation isEqualToString:@"*"]){
        NSLog(@"*");
        double result = [strFirstNum doubleValue]*[strSecondNum doubleValue];
        self.ResultTextField.text = [NSString stringWithFormat:@"%f",result];
    }
    else if([strOperation isEqualToString:@"/"]){
        NSLog(@"/");
        //判断除数不能为0
        if ([strSecondNum isEqualToString:@"0"]) {
            NSLog(@"除数不能为0");
            UIAlertView* tempAlert = [[UIAlertView alloc] initWithTitle:@"警告" message:@"除数不能为0" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil];
            [tempAlert show];
        }else{
            double result = [strFirstNum doubleValue]/[strSecondNum doubleValue];
            self.ResultTextField.text = [NSString stringWithFormat:@"%f",result];
        }
    }
}

恩,这样写肯定能够实现功能。但是如果进行更多的运算,例如增加开平方、乘方运算,增加100种运算,那么是不是要增加100个else if判断语句呢?如果这样去做每次都要去修改这部分代码,这样有悖于可扩展性原则。所以我们需要引入简单工厂模式,把运算给抽象出来,并且加入运算工厂用于接收用户的操作。

注释:这里我们把运算这个动作给抽象出来,当做一个对象,可能很多人觉得有点迷糊。我们知道,面向对象编程是不同于面向过程编程的,通常将一个事物给抽象成一个类,类具有属性和方法;那么我们也可以把一个动作进行抽象,例如此处的运算Operation,它具有两个属性(前一个操作数和后一个操作数),它具有的方法就是获取运算的结果。所以深入理解面向对象编程,还有很多的路要走。

那么此处我们可以抽象出一个UML图,如下所示,

与上面的UML结构图类似,这里再简单解释一下,加、减、乘、除四个运算符都继承自父类Operation,有两个属性和一个操作方法,这些加减乘除的对象并不是直接在ViewController中创建,而是根据输入操作符,由简单工厂OperationFactory来创建。

(1)创建一个协议OprationProtocol,由父类Operation来遵从该协议

/*
 *  操作方法协议接口
 */
@protocol OperationProtocol <NSObject>
-(double)getResult;
@end

(2)定义加减乘除操作的父类Operation

#import OperationProtocol.h
/*
 *  操作方法父类
 */
@interface Operation : NSObject<operationprotocol>
@property double firstNum;//第一个操作数
@property double secondNum;//第二个操作数 
@end

(3)加减乘除实现类,此处以"加"举例说明,

//OperationAdd.h文件
#import Operation.h
/*
 *  加法实现类
 */
@interface OperationAdd : Operation
@end

//OperationAdd.m文件
#import "OperationAdd.h"
@implementation OperationAdd
-(double)getResult
{
    double result = 0;
    result = self.firstNum+self.secondNum;//"+"是OperationAdd时候使用,"+-*/"分别对应"加减乘除"
    return result;
}
@end

(4)简单工厂类的代码,

//OpeartionFactory.h file
#import Operation.h
#import OperationAdd.h
#import OperationSub.h
#import OperationMultiply.h
#import OperationDivide.h
/*
 *  操作工厂类
 */
@interface OperationFactory : NSObject
 
//获得操作对象
+(Operation*)createOperate:(NSString*)operateStr;
 
@end

//OpeartionFactory.m file
#import "OperationFactory.h"
@implementation OperationFactory

+(Operation*)createOperate:(NSString*)operateStr
{
    Operation* oper = nil;
    //根据不同的操作符,创建不同的操作对象,"+-*/"分别对应"加减乘除"
    if ([operateStr isEqualToString:@"+"]) {
        oper = [[OperationAdd alloc] init];
    }else if ([operateStr isEqualToString:@"-"]){
        oper = [[OperationSub alloc] init];
    }else if ([operateStr isEqualToString:@"*"]){
        oper = [[OperationMultiply alloc] init];
    }else if ([operateStr isEqualToString:@"/"]){
        oper = [[OperationDivide alloc] init];
    }
    return oper;
}
@end

(5)客户端代码,在ViewController中使用OperationFactory

- (IBAction)clickingOperation:(id)sender {
    NSString* strFirstNum = self.firstNumTextField.text;
    NSString* strSecondNum = self.secondNumTextField.text;
    Operation* oper;
    oper = [OperationFactory createOperate:self.operationTextField.text];
    oper.firstNum = [strFirstNum doubleValue];
    oper.secondNum = [strSecondNum doubleValue];
    self.resultTextField.text = [NSString stringWithFormat:@%f,[oper getResult]];
}

这样的话ViewController中的代码看起来就简洁明了,而且易于扩展。

那么我们根据ViewController中的代码,分析一下使用思路,把操作类类比成一个容器,它有输入端(操作符号、第一个操作数、第二个操作数)和输出端(运算结果),如下图所示,

所以上面的代码将ViewController的TextField中的输入内容拿过来创建操作对象,并且把操作运算的逻辑放在了Operation及其子类中实现,然后将结果返回给ViewController,这样减少了ViewController的逻辑代码。

通过简单工厂模式的重构,我们就是闲了低耦合度的代码结构,做到了对外扩展开放,对修改关闭。如果再增加任何的操作方法,只需要继承操作方法父类,新建一个操作子类,并且在简单工厂类里面多添加一个else if的判断即可。

五、优缺点

优点:简单工厂模式的优点是客户端可以直接消费产品,而不必关心具体产品的实现,消除了客户端直接创建产品对象的责任,实现了对责任的分割。

缺点是工厂类几种了所有产品的创建逻辑,一旦不能正常工作,整个系统都会受到影响,而且当产品类多结构复杂的时候,把所有创建工作放进一个工厂中来,回事后期程序的扩展较为困难。

通过优缺点的分析,我们可以再如下场景中使用简单工厂模式:

(1)工厂类负责创建的对象较少时;

(2)客户端只知道传入工厂类的参数,对于如何创建对象的逻辑不必关心时。

六、参考博客

(1)iOS设计模式浅析值简单工厂模式(SimpleFactory)

(2)设计模式深入学习iOS版(2)简单工厂模式

(3)计算机简单工厂模式示例代码

召唤攻城狮
粉丝 180
博文 53
码字总数 49671
作品 0
玉林
私信 提问
加载中
请先登录后再评论。
Netty那点事(三)Channel与Pipeline

Channel是理解和使用Netty的核心。Channel的涉及内容较多,这里我使用由浅入深的介绍方法。在这篇文章中,我们主要介绍Channel部分中Pipeline实现机制。为了避免枯燥,借用一下《盗梦空间》的...

黄亿华
2013/11/24
2W
22
记一次失败的Perl + Nginx + FastCGI 配置过程

这两天心血来潮,不知道为什么和 Perl + Nginx + FastCGI 配置 耗上了。但是失败了,记录如下: 1)安装Nginx 1.4.3 ,我的是WINDOWS 7 系统,修改配置文件如下: location ~ .(pl|cgi|perl)?...

通吃岛-低手哥
2013/10/27
1.8K
7
访问安全控制解决方案

本文是《轻量级 Java Web 框架架构设计》的系列博文。 今天想和大家简单的分享一下,在 Smart 中是如何做到访问安全控制的。也就是说,当没有登录或 Session 过期时所做的操作,会自动退回到...

黄勇
2013/11/03
3.6K
8
Flappy Bird(安卓版)逆向分析(一)

更改每过一关的增长分数 反编译的步骤就不介绍了,我们直接来看反编译得到的文件夹 方法1:在smali目录下,我们看到org/andengine/,可以知晓游戏是由andengine引擎开发的。打开/res/raw/at...

enimey
2014/03/04
6.2K
18
我的架构演化笔记 功能1: 基本的用户注册

“咚咚”,一阵急促的敲门声, 我从睡梦中惊醒,我靠,这才几点,谁这么早, 开门一看,原来我的小表弟放暑假了,来南京玩,顺便说跟我后面学习一个网站是怎么做出来的。 于是有了下面的一段...

强子哥哥
2014/05/31
976
3

没有更多内容

加载失败,请刷新页面

加载更多

Subversion存储库中“分支”,“标记”和“主干”的含义是什么?

问题: I've seen these words a lot around Subversion (and I guess general repository) discussions. 我已经在Subversion(我猜通用存储库)讨论中看到了很多这样的话。 I have been us......

富含淀粉
42分钟前
5
0
《Java8实战》笔记(03):Lambda表达式

本文源码 Lambda 管中窥豹 可以把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。 Lambda表达...

巨輪
43分钟前
7
0
从其他文件夹导入文件 - Importing files from different folder

问题: I have the following folder structure. 我有以下文件夹结构。 application/app/folder/file.py and I want to import some functions from file.py in another Python file which r......

javail
今天
22
0
大数据研发学习之路--Hadoop集群搭建

阅读编译文档 准备一个hadoop源码包,我选择的hadoop版本是:hadoop-2.7.7-src.tar.gz,在hadoop-2.7.7的源码 包的根目录下有一个文档叫做BUILDING.txt,这其中说明了编译hadoop所需要的一些...

DSJ-shitou
今天
8
0
OSChina 周五乱弹 —— 特么是别的公司派来的特洛伊木马吧?

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 小小编辑推荐:《我会守在这里》- 毛不易 《我会守在这里》- 毛不易 手机党少年们想听歌,请使劲儿戳(这里) @FalconChen :股市连跪了五天,...

小小编辑
今天
71
2

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部