<简书 — 刘小壮> http://www.jianshu.com/p/a523144d8d7agit
以前写过一篇关于简单工厂模式的博客,后来再看感受以前写的不太好,并且不够详细。这两天正好有时间,打算把以前简单工厂模式的文章重写,此次要写关于工厂模式的一系列文章,而不仅是一篇文章。github
这系列文章将会从浅入深,讲述三种工厂模式的设计,分别是:简单工厂模式、工厂方法模式、抽象工厂模式。因为__反射机制能够简化工厂模式__,因此这系列文章将会给出没有使用反射机制,和使用了反射机制的两种实现代码。算法
本人理解可能不够深入,这一系列文章中存在的问题,欢迎你们提出,谢谢!编程
简单工厂模式中定义一个抽象类,抽象类中声明公共的特征及属性,抽象子类继承自抽象类,去实现具体的操做。工厂类根据外界需求,在工厂类中建立对应的抽象子类实例并传给外界,而对象的建立是由外界决定的。外界只须要知道抽象子类对应的参数便可,而不须要知道抽象子类的建立过程,在外界使用时甚至不用引入抽象子类。设计模式
简单工厂模式将抽象子类的建立,和关于抽象子类相关的业务逻辑分离,下降对象间的耦合度。因为工厂类只是为外界建立对象,因此并不须要实例化工厂类对象,只须要为外界提供类方法便可。外界须要什么类型的抽象子类,只须要传递对应的参数便可。外界不须要知道具体的抽象子类,只须要使用抽象类便可。工具
简单工厂模式主要适用于抽象子类的业务逻辑相同,但具体实现不一样的状况。不一样的操做子类执行一样的方法,最后的结果倒是不一样的,这也是多态的一种表现方式。学习
这里用一个简单的加减乘除的基础运算例子看成需求,下面的__UML__类图和代码都会依据这个场景来实现。假设如今须要实现一个简单的加减乘除运算,这些运算具体操做都是相似的,都有两个被操做的值和一个运算方法,只是运算符不一样,这种状况就适合用简单工厂模式。优化
根据上面提出的业务场景来画一张类图,因为在__Mac__中没找到比较好的画类图的工具,因此简单的画了一下,主要体现具体结构。atom
从上面图中咱们能够看出,图中定义了一个运算抽象类,全部的运算抽象子类继承自这个运算抽象类。运算抽象类有两个参与运算的属性,经过调用getResult
方法来获取这两个值最后运算的结果,调用方式都同样,只是最后的结果不一样。抽象类并不参与运算,运算的结果经过运算抽象子类重载getResult
方法去实现。.net
上图中还定义了一个简单工厂类,这个简单工厂类就是用于实现运算抽象子类实例化的逻辑,经过外界传进来的type
参数,并将实例完成的运算操做类返回。
[@interface](https://my.oschina.net/u/996807) Operation : NSObject [@property](https://my.oschina.net/property) (nonatomic, assign) CGFloat numberOne; [@property](https://my.oschina.net/property) (nonatomic, assign) CGFloat numberTwo; - (CGFloat)getResult; [@end](https://my.oschina.net/u/567204) @implementation Operation - (CGFloat)getResult { return 0; } @end
@interface OperationAdd : Operation @end @implementation OperationAdd - (CGFloat)getResult { return self.numberOne + self.numberTwo; } @end @interface OperationSub : Operation @end @implementation OperationSub - (CGFloat)getResult { return self.numberOne - self.numberTwo; } @end @interface OperationMul : Operation @end @implementation OperationMul - (CGFloat)getResult { return self.numberOne * self.numberTwo; } @end @interface OperationDiv : Operation @end @implementation OperationDiv - (CGFloat)getResult { if (self.numberTwo == 0) { NSLog(@"除数不能为零"); return 0; } else { return self.numberOne / self.numberTwo; } } @end
static NSString *kOperationAdd = @"OperationAdd"; static NSString *kOperationSub = @"OperationSub"; static NSString *kOperationMul = @"OperationMul"; static NSString *kOperationDiv = @"OperationDiv";
@interface OperationFactory : NSObject + (Operation *)CreateOperationWithType:(NSString *)type; @end @implementation OperationFactory + (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; } @end
- (void)viewDidLoad { Operation *oper = [OperationFactory CreateOperationWithType:kOperationAdd]; oper.numberOne = 13; oper.numberTwo = 24; NSLog(@"result : %f", [oper getResult]); }
到目前为止简单工厂模式的代码就写完了,能够看到外界想进行什么类型的运算,只须要将传入的运算类型参数改一下便可,工厂类就会实例化不一样的抽象子类进行运算。可是这种工厂类的设计,有一个很大的问题,就在于每次增长或删除某个算法时,都须要对工厂类进行修改,这是不符合__开放封闭原则__的。对于这个问题,咱们后面会经过__反射机制__来进行处理。
工厂模式也是对__面向对象编程__三大特性之一的__多态__的一个很好的表述,下面先简单的介绍一下多态的特性。
__面向对象编程三大特性__之一就有多态,多态是指在程序运行时,相同的消息可能会发给继承自同一个父类的不一样子类型的对象,虽然是同一个方法,可是运行时系统会根据当前对象所属的子类型做出不一样的响应。
面向对象三大特性中,继承和封装都是为了代码重用,继承能够继承自父类的特征和属性,封装能够将实现细节封装,外界调用实现某些功能。而多态则是为了接口重用。
多个子类继承同一个父类,就会具备和父类相同的行为和特征,子类能够对父类的方法进行重写,因此可能同一个方法每一个子类的实现都不一样。经过父类指针指向任意子类对象并调用相同方法,可能会获得不一样的结果。
简单的说就是系统容许将当前类的指针,指向任何继承自当前类的子类,而且不会报错。因为子类继承自父类,因此和父类有相同的特征(方法)。当前类的指针向指向的子类对象发送消息,系统会根据具体的子类对父类方法的实现,做出不一样的响应。
例以下面这行代码:
Operation *obj = [OperationFactory CreateOperationWithType:kOperationAdd];
在上面这个例子中,OperationFactory
工厂类将会返回Operation
的子类实例,Operation
的子类分别继承自同一父类,而且对其getResult
方法进行了重写。Operation
实例化的obj
指针可能指向任何Operation
的子类,并对其发送getResult
消息。最终的结果会根据obj
指针指向的子类有不一样的结果,这就是__多态__。
我对多态的了解很是浅薄,有不对之处还请多多指出,这里只是顺带提了一下。
我以前写过一篇文章,详细讲了一下反射机制,因此这里不就对反射机制详细介绍了。
在上面的代码中,咱们会发现工厂类建立抽象子类的代码都是相同的,只是建立的具体对象不一样,并且若是抽象子类不少的话,会有过多的条件语句。编程中这种重复代码咱们都要将其简化,否则写出的代码就像垃圾代码同样,这也是新手和老手的区别之一。
在这里咱们能够利用__反射机制__来简化代码,根据外面须要的操做子类的类型,反射出具体的类。在上面咱们已经定义了一些NSString
类型的静态变量,这些静态变量的值就是反射须要的字符串,外界只须要使用这些静态变量便可,不用本身手打字符串,也防止了错误的发生。修改以后外界不须要发生任何变化,只须要知道这些静态变量便可,只对工厂类进行修改。
只需将OperationFactory
的建立方法改一下实现,其余地方不受影响。
+ (Operation *)CreateOperationWithType:(NSString *)type { return [NSClassFromString(type) new]; }
改完以后的代码很是符合面向对象编程的__开放封闭原则,即当外界需求发生变化时,只对现有代码进行扩展,不对其原有代码进行修改__的原则。
如今假设再增长一个其余运算功能,只须要再建立一个继承自抽象类的抽象子类,在抽象子类中重写getResult
方法来实现运算,而且在上面定义的静态变量中加入一个对应的变量。其余地方都不会受到影响,这就是一个比较好的__面向对象__的设计。
到此为止,咱们简单工厂模式就讲完了,后续还有两篇文章继续讲工厂方法模式和抽象工厂模式的文章,文章中不足之处,但愿你们多多提出,谢谢!
前段时间写了关于工厂模式的系列文章,这系列文章理解起来比较难懂。应广大读者的须要,这段时间专门给这系列文章补了Demo
。
Demo
只是来辅助读者更好的理解文章中的内容,应该博客结合Demo
一块儿学习,只看Demo
仍是不能理解更深层的原理。Demo
中代码都会有注释,各位能够打断点跟着Demo
执行流程走一遍,看看各个阶段变量的值。
Demo地址:刘小壮的Github