设计模式系列目录
系列前言
最近思考了一下这两年的工作:做Android的时候一直看Android知识,做iOS的时候一直学iOS的东西。其实看起来感觉这样没什么问题,但仔细想想,我发现自己一直忽略了一大片知识点,那就是软件工程。不同的语言,不同的开发方向的确在代码上有千差万别,但是回到软件架构上来看,所有的编程思想都是相通的,比如说算法,再比如说设计模式。算法这点可能在移动开发中用得较少,但设计模式是必不可少的。我回想了一下,虽说写了不少代码,也考虑过一些关于模块代码结构的设计,但还是缺乏对这一块的系统了解。所以就找了一本众人推荐的书——《大话设计模式》来看。这本书写的的确好,通俗易懂,所以在这里我也推荐一下。这本书看了几个章节我就有一种受人点拨的感觉,明显感觉到如果我把这本书吃透,编码水平肯定能提高一个level。想到我的读书列表还有几本受到程序员追捧的大作要看,突然有种迫不及待就要一本一本读下去的感觉。不过读书可不是读一遍就完事的,关键就在于悟。进步也不能急,一点一点来吧。加油!
23种设计模式
关于设计模式最好的书应该是GoF的《设计模式》了,其中列出了23种设计模式,这里先列出来,后面写完对应博客会把这里改为文章链接方便查看。
- Singleton 单例模式
- Abstract Factory 抽象工厂模式
- Builder 生成器模式
- Factory Method 工厂方法模式
- Prototype 原型模式
- Adapter 适配器模式
- Bridge 桥接模式
- Composite 组合模式
- Decorator 装饰模式
- Facade 外观模式
- Flyweight 享元模式
- Proxy 代理模式
- Template Method模板方法
- Command 命令模式
- Interpreter 解释器模式
- Mediator 中介者模式
- Iterator 迭代器模式
- Observer 观察者模式
- Chain Of Responsibility 职责链模式
- Memento 备忘录模式
- State 状态模式
- Strategy 策略模式
- Visitor 访问者模式
- Design Principles 设计原则
实现四则运算
下面直接先上代码,因为一开始就说太多概念容易让人看不下去。 对于四则运算,也就是简单的加减乘除,实现起来并不难,但我们要用面向对象的角度去思考代码。加减乘除属于四种不同且独立的功能,所以应该分别地实现与封装,这样修改代码的时候也会方便一些,不会误改其他功能的代码。 另外,对于这四种运算都有一个相同点,那就是运算都需要两个数字来完成,考虑到这一点,就可以设计一个基类,在基类中定义两个用于计算的变量,再声明一个获取计算结果的方法。之后,四则运算分别继承这个基类,各自实现返回结果的方法。
代码语言:javascript复制///Operation.h
@interface Operation : NSObject
@property (nonatomic, assign) CGFloat number1;
@property (nonatomic, assign) CGFloat number2;
- (CGFloat)getResult;
@end
///Operation.m
@interface Operation : NSObject
@property (nonatomic, assign) CGFloat number1;
@property (nonatomic, assign) CGFloat number2;
- (CGFloat)getResult;
@end
///OpAdd.h
@interface OpAdd : Operation
@end
///OpAdd.m
@implementation OpAdd
- (CGFloat)getResult {
return self.number1 self.number2;
}
@end
///OpMns.m
@implementation OpMns
- (CGFloat)getResult {
return self.number1 - self.number2;
}
@end
///OpMul.m
@implementation OpMul
- (CGFloat)getResult {
return self.number1 * self.number2;
}
@end
///OpDiv.m
@implementation OpDiv
- (CGFloat)getResult {
if (self.number2 == 0) {
NSLog(@"除数不能为零");
return 0;
} else {
return self.number1 / self.number2;
}
}
@end
好了,功能封装完毕,下面就可以直接用这些写好的功能了,比如我要做加法
代码语言:javascript复制Operation *operation = [OpAdd new];
operation.number1 = 1;
operation.number2 = 2;
NSLog(@"operation result: %f", [operation getResult]);
但这样做的话我每次做运算时都需要知道我到底要实例化谁。为了方便起见,可以设计一个工厂类,专门用来做这个实例化的过程,这就是简单工厂模式。
代码语言:javascript复制typedef NS_ENUM(int, TYPE_OPERATION) {
OPERATION_ADD = 0,
OPERATION_MNS,
OPERATION_MUL,
OPERATION_DIV
};
@interface OperationSimpleFactory : NSObject
(Operation *)CreateOperationWithType:(enum TYPE_OPERATION)type;
@end
@implementation OperationSimpleFactory
(Operation *)CreateOperationWithType:(enum TYPE_OPERATION)type {
Operation *op = nil;
switch (type) {
case OPERATION_ADD:
op = [OpAdd new];
break;
case OPERATION_MNS:
op = [OpMns new];
break;
case OPERATION_MUL:
op = [OpMul new];
break;
case OPERATION_DIV:
op = [OpDiv new];
break;
default:
break;
}
return op;
}
@end
设计好工厂就可以直接使用工厂类实例化合适的对象,通过多态,返回父类的方式实现运算。
代码语言:javascript复制int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
Operation *op = [OperationSimpleFactory CreateOperationWithType:OPERATION_ADD];
op.number1 = 10;
op.number2 = 20;
NSLog(@"operation result: %f", [op getResult]);
}
return 0;
}
这里工厂类的CreateOperationWithType:
方法是类方法,所以使用的时候不需要实例化工厂类,直接使用该方法传入参数就能够获得对应的运算实例。
但对于这段代码,如果我想要增加一个新的计算方法,比如用两个数字取log,这样我就需要首先创建一个计算log的功能类,然后修改工厂类的代码,增加一个switch分支。但是修改工厂类并不符合开放封闭原则,这里可以使用反射机制进行处理。
代码语言:javascript复制static NSString *kOperationAdd = @"OpAdd";
static NSString *kOperationMns = @"OpMns";
static NSString *kOperationMul = @"OpMul";
static NSString *kOperationDiv = @"OpDiv";
@interface OperationSimpleFactory : NSObject
(Operation *)CreateOperationWithType:(NSString *)type;
@end
@implementation OperationSimpleFactory
(Operation *)CreateOperationWithType:(NSString *)type {
return [NSClassFromString(type) new];
}
@end
这里定义几个字符串常量,字符串内容和功能类名保持一致,将字符串作为参数即可。
简单工厂模式
简单工厂模式中定义一个抽象类,抽象类中声明公共的特征及属性,抽象子类继承自抽象类,去实现具体的操作。工厂类根据外界需求,在工厂类中创建对应的抽象子类实例并传给外界,而对象的创建是由外界决定的。外界只需要知道抽象子类对应的参数即可,而不需要知道抽象子类的创建过程,在外界使用时甚至不用引入抽象子类。
简单工厂模式将操作对象的创建,和关于操作对象相关的业务逻辑分离开,降低操作对象的耦合度。由于工厂类只是为外界创建对象,所以并不需要实例化工厂类对象,只需要为外界提供类方法即可。外界需要什么类型的抽象子类,只需要传递对应的参数即可。
UML类图
小结
在简单工厂模式中,一个工厂类负责所有产品对象的创建,这个工厂类的职责大大增加,可能客户端对于某些产品的创建方式会有不同的要求,这样的话,就要不断的修改工厂类,增加相应的逻辑,不利于后期的代码维护。 另外,由于简单工厂模式使用静态方法创建,这就导致静态方法无法被继承。 所以,简单工厂模式适用于创建的对象比较少或简单的情况。
Swift代码
因为最近也在看Swift,所以会用Swift做一些练习练习
代码语言:javascript复制class Operation {
var number1: CGFloat = 0.0
var number2: CGFloat = 0.0
func getResult() -> CGFloat {
return 0
}
}
class OpAdd: Operation {
override func getResult() -> CGFloat {
return self.number1 self.number2
}
}
class OpMns: Operation {
override func getResult() -> CGFloat {
return self.number1 - self.number2
}
}
class OpMul: Operation {
override func getResult() -> CGFloat {
return self.number1 * self.number2
}
}
class OpDiv: Operation {
override func getResult() -> CGFloat {
if self.number2 == 0 {
print("除数不得为零")
return 0
} else {
return self.number1 / self.number2
}
}
}
enum OperationType {
case OperationAdd
case OperationMns
case OperationMul
case OperationDiv
}
class OperationSimpleFactory {
static func CreateOperationWithType(type: OperationType) -> Operation {
var operation: Operation
switch type {
case .OperationAdd:
operation = OpAdd()
case .OperationMns:
operation = OpMns()
case .OperationMul:
operation = OpMul()
case .OperationDiv:
operation = OpDiv()
}
return operation
}
}
let op: Operation = OperationSimpleFactory.CreateOperationWithType(OperationType.OperationAdd)
op.number1 = 10
op.number2 = 20
print("result by Add is", op.getResult())