本文将通过一个计算器的实现和逐步优化来了解简单工厂模式。
实现一个计算器最简单的就是判断运算符号,然后进行直接运算。(这里假设输入的num1 、num2 和operator 都是正确的,不验证输入规范与否。 num1 、num2 和operator 是3个UITextField)
NSString * resultStr = @"";
if ([operator.text isEqualToString:@"+"]) {
resultStr = [NSString stringWithFormat:@"result:%.2f",[_num1.text floatValue] + _num2.text.floatValue ];
}else if ([operator.text isEqualToString:@"-"]) {
resultStr = [NSString stringWithFormat:@"result:%.2f",[_num1.text floatValue] - _num2.text.floatValue ];
}else if ([operator.text isEqualToString:@"*"]) {
resultStr = [NSString stringWithFormat:@"result:%.2f",[_num1.text floatValue] * _num2.text.floatValue ];
}else if ([operator.text isEqualToString:@"/"]){
resultStr = [NSString stringWithFormat:@"result:%.2f",[_num1.text floatValue] / _num2.text.floatValue ];
}
NSLog(@"%@",resultStr);
//显示结果
resultLabel.text = resultStr;
业务逻辑完全实现了,没有错,但是很糟糕,违背了面向过程编码的思想。
所有编程初学者都会有这样的问题:
- 碰到问题就直觉的用计算机能够理解的逻辑来描述和表达待解决的问题及具体的求解过程。这其实是用计算机的方式去思考。
- 这样的程序只能满足当前的需求,程序不易维护,不易扩展,更不容易复用。从而达不到高质量的代码。
- 如果对于面向对象编程基础还有问题,请翻看一下设计模式 - 面向对象基础。
举个例子:
中国有四大发明,火药、指南针、造纸术都是从无到有的创造或发现,而活字印刷是思想的成功,面向对象的胜利。
- 只需要改需要改的字 --- 可维护
- 用完之后还可以在下次印刷中使用 --- 可复用
- 如要加字,只需另刻所加的字 --- 可扩展
- 不管是横竖排列印刷都可以。 --- 灵活性好
以上的四点优势就是面向对象分析设计编程思想的好处。在我们用面向对象语言编写程序的时候,可以通过封装、继承、多态把程序的耦合度降低,用设计模式使得程序更加的灵活,容易修改,并且易于复用。
复用:复用不是复制,而且编程有一原则,就是用尽可能的方法避免重复。
业务的封装:就是让业务逻辑和界面逻辑分开,让他们之间的耦合度下降,只有分离开,才可以达到容易维护和扩展。
聚合:聚合表示一种“弱拥有”关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分。(雁群和大雁:大雁是群居动物,每只大雁都属于一个雁群,一个雁群可以有多只大雁,所以它们满足聚合关系。)
合成:合成也有翻译成组合,是一种“强拥有”关系,体现了严格的部分和整体,部分和整体的生命周期是一样的。(鸟和翅膀的关系就是组合关系)
如果不只是简单四则运算,而是加上更多的运算方法,难道要判断N多个if-else?
那么该怎么一步步优化呢?
首先就是将业务逻辑和界面逻辑分离,让他们的耦合度降低,只有分离才能达到容易维护或扩展。
把运算逻辑完全抽离出来:
Operation.h
@interface Operation : NSObject
-(NSString *)GetResultWithNum1:(double)num1 Num2:(double)num2 operator:(NSString *)operator;
@end
Operation.m
#import "Operation.h"
@implementation Operation
-(NSString *)GetResultWithNum1:(double)num1 Num2:(double)num2 operator:(NSString *)operator{
NSString * resultStr = @"";
if ([ operator isEqualToString:@"+"]) {
resultStr = [NSString stringWithFormat:@"result:%.2f", num1 + num2 ];
}else if ([ operator isEqualToString:@"-"]) {
resultStr = [NSString stringWithFormat:@"result:%.2f", num1 - num2 ];
}else if ([ operator isEqualToString:@"*"]) {
resultStr = [NSString stringWithFormat:@"result:%.2f", num1 * num2 ];
}else if ([ operator isEqualToString:@"/"]){
resultStr = [NSString stringWithFormat:@"result:%.2f", num1 / num2 ];
}
return resultStr;
}
@end
在需要调用计算的方法中实例化Operation
类,然后调用GetResultWithNum1:Num2:operator:
方法。
Operation *op = [[Operation alloc]init];
_resultLB.text = [op GetResultWithNum1:_num1.text.floatValue Num2:_num2.text.floatValue operator:operator.text];
上面的代码只是实现了面向对象的三大特性之一 -- 封装。但是这样的代码不能很灵活的修改和扩展,如果再增加一个开根号运算,就要在Operation
类中增加判断,但是如果要是再多的话,容易出错,可读性变差。
接下来利用继承和多态来继续优化。(如果还是对继承和多态不是很理解请看设计模式 - 面向对象基础,里面有简单的介绍。)。
第一步:先修改Operation
类使其变成一个抽象类,然后分别建4个继承自Operation
类加减乘除的类。
Operation.h
@interface Operation : NSObject
@property(nonatomic) double num1;
@property(nonatomic) double num2;
//抽象方法
-(NSString *)getResult;
@end
Operation.m
@implementation Operation4
-(NSString *)getResult{
return @"计算结果";
}
@end
4个运算类: .h
文件中不用声明任何属性和方法。只需要在.m
中实现父类的getResult
方法即可。
// 加
@implementation Operation_Add
-(NSString *)getResult{
return [NSString stringWithFormat:@"result:%.2f", self.num1 + self.num2];
}
@end
// 减
@implementation Operation_Sub
-(NSString *)getResult{
return [NSString stringWithFormat:@"result:%.2f", self.num1 - self.num2];
}
@end
// 乘
@implementation Operation_Mul
-(NSString *)getResult{
return [NSString stringWithFormat:@"result:%.2f", self.num1 * self.num2];
}
@end
// 除
@implementation Operation4_Div
-(NSString *)getResult{
return [NSString stringWithFormat:@"result:%.2f", self.num1 / self.num2];
}
@end
这样需要修改那个类就只需要提供那个类就好了,不用再去看其他的类。
但是这样我们不知道什么时候该用那个类来,还是要在调用的时候去判断,写n多的if-else。
最后一步优化就是创建一个简单工厂的简单运算OperationFactory
类来。来判断什么时候调用那个运算类。
工厂:用一个单独的类来创造实例的过程
OperationFactory.h
//引入运算抽象类
#import "Operation.h"
@interface OperationFactory :NSObject
+(Operation*)createOperate:(NSString *)operate;
@end
OperationFactory.m
//引入加减乘除类
#import "Operation_Add.h"
#import "Operation_Div.h"
#import "Operation_Mul.h"
#import "Operation_sub.h"
@implementation OperationFactory
+(Operation*)createOperate:(NSString *)operate{
Operation *op = nil;
if ([operate isEqualToString:@"+"]) {
op = [Operation_Add new];
}else if ([operate isEqualToString:@"-"]) {
op = [Operation_sub new];
}else if ([operate isEqualToString:@"*"]) {
op = [Operation_Mul new];
}else if ([operate isEqualToString:@"/"]) {
op = [Operation_Div new];
}
return op;
}
@end
这样就可以指导在什么时候调用什么运算类了。
只需要输入运算符号,工厂就能实例化出合适的对象,通过多态,返回父类的方式实现计算器的结果。
//引入 OperationFactory和Operation类
Operation4 *op = [OperationFactory createOperate:operator.text];
op.num1 = _num1.text.doubleValue;
op.num2 = _num2.text.doubleValue;
NSLog(@"%@",resultStr);
_resultLable.text = [op getResult];
至此一个简单的简单工厂模式示例就算完成了。最后放一张这几个类的结构图。
{578AD73E-A83F-0C49-1965-25BA045502F2}.png
网友评论