在了解设计模式之前先了解下设计时的原则;
1. 设计原则
1.1 单一职责原则; 一个类只负责一个功能;
UIView
和CALayer
的关系;这篇文章结尾
1.2 开闭原则; 对修改关闭, 对扩展开放;
后期迭代类, 函数, 功能模块时尽量不去更改, 而是通过继承和合成复用方式解决问题;
1.3 接口隔离原则; 将协议细分为多个专门的协议, 而不是一个庞大的多功能协议;
UITableView
的dataSource
和delegate
的模式, 一个负责数据一个负责处理代理回调;
1.4 依赖倒置原则; 抽象内容不应该依赖具体实现, 具体实现可以依赖于抽象;
1.5 里氏替换原则; 父类可以被子类无缝替换, 且原有功能不受影响;
KVO
的实现过程, 中系统自动创建NSKVONotifying_子类
替换原有类进而实现功能;
1.6 迪米特法则; 一个对象应该尽量少的去处理管理其他对象;
实现高内聚低耦合;模块之间的解耦;
1.7 合成复用原则; 尽量使用对象组合来达到复用的目的, 而不是继承;
继承时一旦基类发生变化, 那么他的派生类都会跟着变化;RXSwift
中有才采用这种策略;
2. 设计模式
2.1 责任链模式;
责任链模式当主要思想是对象引用同一个类型的另一个对象; 每个对象的实现方法都一样, 这样可以形成一种模式就是如果当前对象不处理这个任务, 就把他抛给链上的另一个对象;实现方式有继承
和自我实现(next指针)?
等方式;
Cocoa
中的经典用法就是UI
的响应链;
优点:
- 1.解耦请求的发送者和处理者;
- 2.简化对象, 不需要关心结构;
- 3.链内的成员可以随时增减;
缺点:
- 1.出现问题调试较为麻烦;
- 2.任务并不一定保证能能被处理掉;
责任链实现的代码讲解:
#链条开始的类
#import <Foundation/Foundation.h>
@class HandleModel;
typedef void(^HandleSuccess)(BOOL handled);
typedef void(^HanleResult)(HandleModel * _Nullable handler, BOOL handled);
NS_ASSUME_NONNULL_BEGIN
@interface HandleModel : NSObject
///下一个响应者, 构成响应链的关键
@property (nonatomic, strong) HandleModel *nextHandler;
//响应者的处理方法
- (void)handle:(HanleResult)resultB taskType:(NSInteger)type;
///各个业务在该方法中做实际的处理事宜
- (void)handleBusiess:(HandleSuccess)callB taskType:(NSInteger)type;
@end
NS_ASSUME_NONNULL_END
#import "HandleModel.h"
@implementation HandleModel
///责任链入口方法, 如果当前类不处理就向链条的下一个指派
- (void)handle:(HanleResult)resultB taskType:(NSInteger)type{
HandleSuccess successB = ^(BOOL success){
if (success) {
resultB(self, success);
}else {
///当前不处理, 沿着责任链, 指派给下一个业务处理
if (self.nextHandler) {
[self.nextHandler handle:resultB taskType:type];
}else {
///没有处理者, 传为nil
resultB(nil, NO);
}
}
};
///当前业务进行处理
[self handleBusiess:successB taskType:type];
}
- (void)handleBusiess:(HandleSuccess)callB taskType:(NSInteger)type{
if (type < 10) {
///执行逻辑处理, 处理完成后回调
callB(YES);
}else {
callB(NO);
}
}
@end
#链条上的另一个响应者实现, 继承自链条开始的类
#import "HandleModel.h"
NS_ASSUME_NONNULL_BEGIN
@interface HandleModelA : HandleModel
@end
NS_ASSUME_NONNULL_END
#import "HandleModelA.h"
@implementation HandleModelA
//这个方法继承自父类, 逻辑不需变动, 如果当前类不处理就向链条的下一个指派
//- (void)handle:(HanleResult)resultB taskType:(NSInteger)type {
// HandleSuccess successB = ^(BOOL success){
// if (success) {
// resultB(self, YES);
// }else {
// if (self.nextHandler) {
// [self.nextHandler handle:resultB taskType:type];
// }else {
// resultB(nil, NO);
// }
// }
// };
// [self handleBusiess:successB taskType:type];
//}
- (void)handleBusiess:(HandleSuccess)callB taskType:(NSInteger)type{
if (type >= 10 && type < 20) {
///执行逻辑处理, 处理完成后回调
callB(YES);
}else {
callB(NO);
}
}
@end
实际运用:
- (void)responsiblityChain {
///这个数组作用是: 模拟一系列需要处理的任务
NSArray *taskArr = @[@(1), @(3), @(11), @(15), @(45), @(23), @(80), @(24), @(66)];
HandleModel *taskModel = [[HandleModel alloc] init];
HandleModel *taskModelA = [[HandleModelA alloc] init];
HandleModel *taskModelB = [[HandleModelB alloc] init];
HandleModel *taskModelC = [[HandleModelC alloc] init];
///创建一个责任链, 如果当前模型不处理, 就把任务向链中的下一个模型抛
taskModel.nextHandler = taskModelA;
taskModelA.nextHandler = taskModelB;
taskModelB.nextHandler = taskModelC;
///模拟执行多个任务
for (NSNumber *taskNum in taskArr) {
[taskModel handle:^(HandleModel *handler, BOOL handled) {
NSLog(@"任务编号: %@ 执行状态: %d 执行者: %@", taskNum, handled, handler.class);
} taskType:taskNum.integerValue];
}
}
#执行结果为
2019-05-05 16:10:26.395055+0800 DesignMode[7894:497216] 任务编号: 1 执行状态: 1 执行者: HandleModel
2019-05-05 16:10:26.395261+0800 DesignMode[7894:497216] 任务编号: 3 执行状态: 1 执行者: HandleModel
2019-05-05 16:10:26.395370+0800 DesignMode[7894:497216] 任务编号: 11 执行状态: 1 执行者: HandleModelA
2019-05-05 16:10:26.395509+0800 DesignMode[7894:497216] 任务编号: 15 执行状态: 1 执行者: HandleModelA
2019-05-05 16:10:26.395654+0800 DesignMode[7894:497216] 任务编号: 45 执行状态: 1 执行者: HandleModelC
2019-05-05 16:10:26.395768+0800 DesignMode[7894:497216] 任务编号: 23 执行状态: 1 执行者: HandleModelB
2019-05-05 16:10:26.395895+0800 DesignMode[7894:497216] 任务编号: 80 执行状态: 0 执行者: (null)
2019-05-05 16:10:26.396014+0800 DesignMode[7894:497216] 任务编号: 24 执行状态: 1 执行者: HandleModelB
2019-05-05 16:10:26.396124+0800 DesignMode[7894:497216] 任务编号: 66 执行状态: 0 执行者: (null)
2.2 桥接模式;
应用场景, 一个VC
要适配多套数据模型时; 使用桥接模式能优化处理;
![](https://img.haomeiwen.com/i1311960/3f946f1e3574ccb4.png)
代码讲解示例
#抽象业务类持有属性抽象数据请求类
#import <Foundation/Foundation.h>
#import "RequestModel.h"
NS_ASSUME_NONNULL_BEGIN
@interface BusiessModel : NSObject
///桥接模式的核心实现, 抽象类持有;
@property (nonatomic, strong) RequestModel *requestModel;
///处理业务
- (void)handleTask;
@end
NS_ASSUME_NONNULL_END
#.m实现
#import "BusiessModel.h"
@implementation BusiessModel
/**
具体实现的时候会有四种组合去处理业务
BusinessA ---> Request1 Request2
BusinessB ---> Request1 Request2
*/
- (void)handleTask {
[self.requestModel requestData];
}
@end
#请求类的实例
#import "RequestModel.h"
NS_ASSUME_NONNULL_BEGIN
@interface Request1 : RequestModel
///实例实现
- (void)requestData;
@end
NS_ASSUME_NONNULL_END
#.m实现
#import "Request1.h"
@implementation Request1
- (void)requestData {
NSLog(@"获取数据2");
}
@end
#业务类的实例过程
#import "BusiessModel.h"
NS_ASSUME_NONNULL_BEGIN
@interface BusiessA : BusiessModel
///实例实现
- (void)handleTask;
@end
NS_ASSUME_NONNULL_END
#.m实现
#import "BusiessA.h"
@implementation BusiessA
- (void)handleTask {
///在调用父类之前可以处理一些逻辑;
///调用父类实现
[super handleTask];
///在调用父类之后仍然可以处理一些逻辑;
}
@end
///桥接模式
- (void)bridge {
///根据业务情形选择使用BusiessA或者BusiessB
BusiessModel *businessM = [[BusiessA alloc] init];
///根据业务情形选择使用Request1或者Request2
RequestModel *requestM = [[Request2 alloc] init];
///抽象类的逻辑实例实现
businessM.requestModel = requestM;
///真正处理业务
[businessM handleTask];
}
2.3 适配器模式;
适用场景: 工程中的年代很久远的类, 并且逻辑已经很成熟, 基本上没什么问题, 如果要对其更改或者扩展, 直接更改是不合适的, 这时通过适配器模式就行扩展比较合适;
代码讲解示例
#一个年代很久远的类, 功能逻辑已经很完善;
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface RemoteModel : NSObject
///这个类的其中一个功能, 已经相对很完善
- (void)operationTask;
@end
NS_ASSUME_NONNULL_END
#.m实现
#import "RemoteModel.h"
@implementation RemoteModel
///这个类的其中一个功能, 已经相对很完善
- (void)operationTask {
NSLog(@"处理一些逻辑");
}
@end
对其原先逻辑进行扩展
#import <Foundation/Foundation.h>
#import "RemoteModel.h"
NS_ASSUME_NONNULL_BEGIN
@interface NowModel : NSObject
/**
现在想对RemoteModel中 - (void)operationTask; 方法进行添加一些新的逻辑;
因为原来的逻辑已经很完整,完善; 通过适配器模式进行扩展;
*/
@property (nonatomic, strong) RemoteModel *remoteM;
///对原先逻辑进行扩展
- (void)nowOperationTask;
@end
NS_ASSUME_NONNULL_END
#.m实现
#import "NowModel.h"
@implementation NowModel
///对原先逻辑进行扩展
- (void)nowOperationTask {
NSLog(@"先执行添加的新逻辑");
///然后执行原先的逻辑
[self.remoteM operationTask];
NSLog(@"然后执行一些补充的新逻辑");
}
@end
///适配器模式
- (void)adapter {
RemoteModel *remoteModel = [[RemoteModel alloc] init];
NowModel *nowModel = [[NowModel alloc] init];
nowM.remoteM = remoteModel;
[nowModel nowOperationTask];
}
2.4 单例模式;
使用场景, 工程中一些常用的逻辑可以放在单例中, 这样可以快速获取到; 因为单例整个生命周期只会创建一次, 节省资源;
代码示例讲解
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
///遵循这两个协议是为了防止无意中进行了copy或mutableCopy而开辟新地址;
@interface GlobalModel : NSObject<NSCopying, NSMutableCopying>
+ (GlobalModel *)share;
@end
NS_ASSUME_NONNULL_END
#.m实现
#import "GlobalModel.h"
@implementation GlobalModel
+ (GlobalModel *)share {
static GlobalModel * model = nil;
///确保只能执行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
///为什么不能用self进行alloc, 因为重写下面的方法中返回了[self share]会造成循环;
model = [[super allocWithZone:NULL] init];
});
return model;
}
///确保多次alloc也是同一块地址
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
return [self share];
}
///确保即使进行copy了也是同一块地址
- (id)copyWithZone:(NSZone *)zone {
return self;
}
///确保即使进行mutableCopy了也是同一块地址
- (id)mutableCopyWithZone:(NSZone *)zone {
return self;
}
@end
///单例模式
- (void)singleton {
GlobalModel *model = [[GlobalModel alloc] init];
GlobalModel *model1 = [[GlobalModel alloc] init];
GlobalModel *model2 = [model copy];
GlobalModel *model3 = [model mutableCopy];
GlobalModel *model4 = [GlobalModel share];
NSLog(@"model地址: %@", model);
NSLog(@"model1地址1: %@", model1);
NSLog(@"model2地址2: %@", model2);
NSLog(@"model3地址3: %@", model3);
NSLog(@"model4地址4: %@", model4);
}
#不论是几次alloc或者copy, mutableCopy始终是同一块内存地址
2019-05-06 17:19:42.822105+0800 DesignMode[13036:251989] model地址: <GlobalModel: 0x60000174c020>
2019-05-06 17:19:42.822246+0800 DesignMode[13036:251989] model1地址1: <GlobalModel: 0x60000174c020>
2019-05-06 17:19:42.822400+0800 DesignMode[13036:251989] model2地址2: <GlobalModel: 0x60000174c020>
2019-05-06 17:19:42.822511+0800 DesignMode[13036:251989] model3地址3: <GlobalModel: 0x60000174c020>
2019-05-06 17:19:42.822599+0800 DesignMode[13036:251989] model4地址4: <GlobalModel: 0x60000174c020>
参考文章
推荐 面向对象设计原则概述
面向对象设计原则之单一职责原则
面向对象设计原则之开闭原则
面向对象设计原则之接口隔离原则
面向对象设计原则之依赖倒置原则
面向对象设计原则之里氏替换原则
面向对象设计原则之迪米特法则
面向对象设计原则之合成复用原则
iOS 设计模式详解
网友评论