热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

工厂模式三部曲简单工厂模式

2019独角兽企业重金招聘Python工程师标准该文章属于原创,转载请注明:http:www.jianshu.co

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

该文章属于<简书 — 刘小壮>原创&#xff0c;转载请注明&#xff1a;

<简书 — 刘小壮> http://www.jianshu.com/p/a523144d8d7a


之前写过一篇关于简单工厂模式的博客&#xff0c;后来再看感觉之前写的不太好&#xff0c;而且不够详细。这两天正好有时间&#xff0c;打算把之前简单工厂模式的文章重写&#xff0c;这次要写关于工厂模式的一系列文章&#xff0c;而不只是一篇文章。

这系列文章将会从浅入深&#xff0c;讲述三种工厂模式的设计&#xff0c;分别是&#xff1a;简单工厂模式、工厂方法模式、抽象工厂模式。由于__反射机制可以简化工厂模式__&#xff0c;所以这系列文章将会给出没有使用反射机制&#xff0c;和使用了反射机制的两种实现代码。

本人理解可能不够深刻&#xff0c;这一系列文章中存在的问题&#xff0c;欢迎大家提出&#xff0c;谢谢&#xff01;


博客配图

什么是简单工厂模式&#xff1f;

简单工厂模式中定义一个抽象类&#xff0c;抽象类中声明公共的特征及属性&#xff0c;抽象子类继承自抽象类&#xff0c;去实现具体的操作。工厂类根据外界需求&#xff0c;在工厂类中创建对应的抽象子类实例并传给外界&#xff0c;而对象的创建是由外界决定的。外界只需要知道抽象子类对应的参数即可&#xff0c;而不需要知道抽象子类的创建过程&#xff0c;在外界使用时甚至不用引入抽象子类

简单工厂模式将抽象子类的创建&#xff0c;和关于抽象子类相关的业务逻辑分离&#xff0c;降低对象间的耦合度。由于工厂类只是为外界创建对象&#xff0c;所以并不需要实例化工厂类对象&#xff0c;只需要为外界提供类方法即可。外界需要什么类型的抽象子类&#xff0c;只需要传递对应的参数即可。外界不需要知道具体的抽象子类&#xff0c;只需要使用抽象类即可。

简单工厂模式主要包含三部分&#xff1a;
  • 工厂类&#xff1a;根据外界的需求&#xff0c;决定创建并返回哪个具体的抽象子类。
  • 抽象类&#xff1a;定义抽象子类所需的属性和方法&#xff0c;子类通过继承自抽象类获得这些方法。
  • 抽象子类&#xff1a;继承自抽象类&#xff0c;是具体操作的实现者&#xff0c;根据需求重写父类继承过来的方法。

业务场景

简单工厂模式主要适用于抽象子类的业务逻辑相同&#xff0c;但具体实现不同的情况。不同的操作子类执行同样的方法&#xff0c;最后的结果却是不同的&#xff0c;这也是多态的一种表现方式。

这里用一个简单的加减乘除的基础运算例子当作需求&#xff0c;下面的__UML__类图和代码都会依据这个场景来实现。假设现在需要实现一个简单的加减乘除运算&#xff0c;这些运算具体操作都是类似的&#xff0c;都有两个被操作的值和一个运算方法&#xff0c;只是运算符不同&#xff0c;这种情况就适合用简单工厂模式。

UML类图

根据上面提出的业务场景来画一张类图&#xff0c;由于在__Mac__中没找到比较好的画类图的工具&#xff0c;所以简单的画了一下&#xff0c;主要体现具体结构。

简单工厂模式

从上面图中我们可以看出&#xff0c;图中定义了一个运算抽象类&#xff0c;所有的运算抽象子类继承自这个运算抽象类。运算抽象类有两个参与运算的属性&#xff0c;通过调用getResult方法来获取这两个值最后运算的结果&#xff0c;调用方式都一样&#xff0c;只是最后的结果不同。抽象类并不参与运算&#xff0c;运算的结果通过运算抽象子类重载getResult方法去实现。

上图中还定义了一个简单工厂类&#xff0c;这个简单工厂类就是用于实现运算抽象子类实例化的逻辑&#xff0c;通过外界传进来的type参数&#xff0c;并将实例完成的运算操作类返回。

普通方式代码实现

首先定义抽象类&#xff0c;抽象类中将会包含参与运算的抽象子类的属性和行为(方法)。

[&#64;interface](https://my.oschina.net/u/996807) Operation : NSObject
[&#64;property](https://my.oschina.net/property) (nonatomic, assign) CGFloat numberOne;
[&#64;property](https://my.oschina.net/property) (nonatomic, assign) CGFloat numberTwo;
- (CGFloat)getResult;
[&#64;end](https://my.oschina.net/u/567204)&#64;implementation Operation
- (CGFloat)getResult {return 0;
}
&#64;end

定义抽象类之后&#xff0c;需要创建负责具体运算的抽象子类&#xff0c;也就是操作类&#xff0c;简单的定义了一下&#xff0c;代码不太多就全贴出来了。

&#64;interface OperationAdd : Operation
&#64;end&#64;implementation OperationAdd
- (CGFloat)getResult {return self.numberOne &#43; self.numberTwo;
}
&#64;end&#64;interface OperationSub : Operation
&#64;end&#64;implementation OperationSub
- (CGFloat)getResult {return self.numberOne - self.numberTwo;
}
&#64;end&#64;interface OperationMul : Operation
&#64;end&#64;implementation OperationMul
- (CGFloat)getResult {return self.numberOne * self.numberTwo;
}
&#64;end&#64;interface OperationDiv : Operation
&#64;end&#64;implementation OperationDiv
- (CGFloat)getResult {if (self.numberTwo &#61;&#61; 0) {NSLog(&#64;"除数不能为零");return 0;} else {return self.numberOne / self.numberTwo;}
}
&#64;end

下面先定义了四个静态变量&#xff0c;这四个静态变量声明了创建对象的类型&#xff0c;在后面反射部分代码中也会用到这四个静态变量。

static NSString *kOperationAdd &#61; &#64;"OperationAdd";
static NSString *kOperationSub &#61; &#64;"OperationSub";
static NSString *kOperationMul &#61; &#64;"OperationMul";
static NSString *kOperationDiv &#61; &#64;"OperationDiv";

现在具体参与运算的类都已经定义完成&#xff0c;就需要定义工厂类了。工厂类的职责就是根据外界需要&#xff0c;创建对应的抽象子类实例并返回给外界。

&#64;interface OperationFactory : NSObject
&#43; (Operation *)CreateOperationWithType:(NSString *)type;
&#64;end&#64;implementation OperationFactory
&#43; (Operation *)CreateOperationWithType:(NSString *)type {if ([kOperationAdd isEqualToString:type]) {return [OperationAdd new];} else if ([kOperationSub isEqualToString:type]) {return [OperationSub new];} else if ([kOperationMul isEqualToString:type]) {return [OperationMul new];} else if ([kOperationDiv isEqualToString:type]) {return [OperationDiv new];}return nil;
}
&#64;end

上面我们就将工厂设计模式的定义都完成了&#xff0c;现在需要的就是外界直接拿来使用。上面工厂类直接定义的类方法&#xff0c;因为外界获取某个具体的抽象子类时&#xff0c;并没有必要将工厂类实例化&#xff0c;工厂类只是完成一个实例化操作。

- (void)viewDidLoad {Operation *oper &#61; [OperationFactory CreateOperationWithType:kOperationAdd];oper.numberOne &#61; 13;oper.numberTwo &#61; 24;NSLog(&#64;"result : %f", [oper getResult]);
}

到目前为止简单工厂模式的代码就写完了&#xff0c;可以看到外界想进行什么类型的运算&#xff0c;只需要将传入的运算类型参数改一下即可&#xff0c;工厂类就会实例化不同的抽象子类进行运算。但是这种工厂类的设计&#xff0c;有一个很大的问题&#xff0c;就在于每次增加或删除某个算法时&#xff0c;都需要对工厂类进行修改&#xff0c;这是不符合__开放封闭原则__的。对于这个问题&#xff0c;我们后面会通过__反射机制__来进行处理。

工厂模式也是对__面向对象编程__三大特性之一的__多态__的一个很好的表述&#xff0c;下面先简单的介绍一下多态的特性。

简单介绍一下多态

__面向对象编程三大特性__之一就有多态&#xff0c;多态是指在程序运行时&#xff0c;相同的消息可能会发给继承自同一个父类的不同子类型的对象&#xff0c;虽然是同一个方法&#xff0c;但是运行时系统会根据当前对象所属的子类型作出不同的响应。

面向对象三大特性中&#xff0c;继承和封装都是为了代码重用&#xff0c;继承可以继承自父类的特征和属性&#xff0c;封装可以将实现细节封装&#xff0c;外界调用实现某些功能。而多态则是为了接口重用

多个子类继承同一个父类&#xff0c;就会具有和父类相同的行为和特征&#xff0c;子类可以对父类的方法进行重写&#xff0c;所以可能同一个方法每个子类的实现都不同。通过父类指针指向任意子类对象并调用相同方法&#xff0c;可能会得到不同的结果。

简单的说就是系统允许将当前类的指针&#xff0c;指向任何继承自当前类的子类&#xff0c;并且不会报错。由于子类继承自父类&#xff0c;所以和父类有相同的特征(方法)。当前类的指针向指向的子类对象发送消息&#xff0c;系统会根据具体的子类对父类方法的实现&#xff0c;作出不同的响应

例如下面这行代码&#xff1a;

Operation *obj &#61; [OperationFactory CreateOperationWithType:kOperationAdd];

在上面这个例子中&#xff0c;OperationFactory工厂类将会返回Operation的子类实例&#xff0c;Operation的子类分别继承自同一父类&#xff0c;并且对其getResult方法进行了重写。Operation实例化的obj指针可能指向任何Operation的子类&#xff0c;并对其发送getResult消息。最终的结果会根据obj指针指向的子类有不同的结果&#xff0c;这就是__多态__。

我对多态的了解非常浅薄&#xff0c;有不对之处还请多多指出&#xff0c;这里只是顺带提了一下。

配合反射机制优化代码

我之前写过一篇文章&#xff0c;详细讲了一下反射机制&#xff0c;所以这里不就对反射机制详细介绍了。

在上面的代码中&#xff0c;我们会发现工厂类创建抽象子类的代码都是相同的&#xff0c;只是创建的具体对象不同&#xff0c;而且如果抽象子类很多的话&#xff0c;会有过多的条件语句。编程中这种重复代码我们都要将其简化&#xff0c;不然写出的代码就像垃圾代码一样&#xff0c;这也是新手和老手的区别之一。

在这里我们可以利用__反射机制__来简化代码&#xff0c;根据外面需要的操作子类的类型&#xff0c;反射出具体的类。在上面我们已经定义了一些NSString类型的静态变量&#xff0c;这些静态变量的值就是反射需要的字符串&#xff0c;外界只需要使用这些静态变量即可&#xff0c;不用自己手打字符串&#xff0c;也防止了错误的发生。修改之后外界不需要发生任何变化&#xff0c;只需要知道这些静态变量即可&#xff0c;只对工厂类进行修改。

只需将OperationFactory的创建方法改一下实现&#xff0c;其他地方不受影响。

&#43; (Operation *)CreateOperationWithType:(NSString *)type {return [NSClassFromString(type) new];
}

改完之后的代码非常符合面向对象编程的__开放封闭原则&#xff0c;即当外界需求发生变化时&#xff0c;只对现有代码进行扩展&#xff0c;不对其原有代码进行修改__的原则。

现在假设再增加一个其他运算功能&#xff0c;只需要再创建一个继承自抽象类的抽象子类&#xff0c;在抽象子类中重写getResult方法来实现运算&#xff0c;并且在上面定义的静态变量中加入一个对应的变量。其他地方都不会受到影响&#xff0c;这就是一个比较好的__面向对象__的设计。

到此为止&#xff0c;我们简单工厂模式就讲完了&#xff0c;后续还有两篇文章继续讲工厂方法模式和抽象工厂模式的文章&#xff0c;文章中不足之处&#xff0c;希望大家多多提出&#xff0c;谢谢&#xff01;


前段时间写了关于工厂模式的系列文章&#xff0c;这系列文章理解起来比较难懂。应广大读者的需要&#xff0c;这段时间专门给这系列文章补了Demo

Demo只是来辅助读者更好的理解文章中的内容&#xff0c;应该博客结合Demo一起学习&#xff0c;只看Demo还是不能理解更深层的原理Demo中代码都会有注释&#xff0c;各位可以打断点跟着Demo执行流程走一遍&#xff0c;看看各个阶段变量的值。

Demo地址&#xff1a;刘小壮的Github


转:https://my.oschina.net/u/3781127/blog/2876817



推荐阅读
author-avatar
jzhs5340636
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有