模板方法模式是面向对象软件设计中一种非常简单与经常使用的设计模式。它的核心思想是在抽象类的一个方法中定义某些“标准”算法。在这个方法中调用的基本操作应由子类重载来实现。这个方法可以被称为所谓的“模板”,它定义方法实现中缺少了一些针对性的操作。
使用模板方法要思考以下几点:
1.在父类中一次性实现算法中的不可变部分,并将可变的行为留给子类来实现。
2.子类共用的行为应该被提出来放到公共类中, 以避免代码重复。
3.要考虑一些特殊情况特殊处理。这里采用子类的扩展来实现。可以定义一些在特定点调用“钩子”操作方法。子类可以通过对钩子操作的实现从而在这些点上扩展功能。钩子操作默认情况是不对整个模板造成影响的。子类重载后,才为模板算法提供附加的操作。比如项目中的某些数据请求方法要加请求头token之类,但其它大部分网络请求却不需要,就可以采用"钩子"操作来实现。
费话不多说,直接开撸,看下面的demo。
一.先看模板类的实现
声明:
#import@interface MYTableViewVC : UITableViewController
@property (nonatomic, strong) NSMutableArray *dataSourceArr;
/**
* 注册cell
*/
- (void)setupRegisterCellClasses:(NSArray *)registerCellClasses;
/**
* 模板方法中的钩子方法,默认是无操作的,不对模板造成影响
*/
- (void)cellCallBack:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath;
/**
* “标准”算法,子类重载,也是模板方法模式的重点
* 数据请求
*/
- (void)requestDataSuccess:(void (^)(NSArray *dataArr))success failure:(void (^)(NSString *msg))failure;
@end
实现:
#import "MYTableViewVC.h"
@interface MYTableViewVC ()
@property (nonatomic, strong) NSArray *registerCellClasses;
@end
@implementation MYTableViewVC
- (void)viewDidLoad {
[super viewDidLoad];
self.dataSourceArr = [NSMutableArray new];
self.tableView.tableFooterView = [UIView new];
[self setHeaderRefreshView];
[self setFooterRefreshView];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dataSourceArr.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
for (Class objClass in self.registerCellClasses) {
if ([objClass isSubclassOfClass:[UITableViewCell class]]) {
cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass(objClass)];
if (indexPath.row < self.dataSourceArr.count) {
// Configure the cell...
[self cellCallBack:cell indexPath:indexPath];
}
}
}
return cell;
}
/**
* 模板中的钩子方法
*/
- (void)cellCallBack:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath
{
}
/**
* “标准”算法,子类重载
* 数据请求
*/
- (void)requestDataSuccess:(void (^)(NSArray *dataArr))success failure:(void (^)(NSString *msg))failure{
}
/**
* 上拉刷新
*/
- (void)setHeaderRefreshView{
//这里要父类中实现具体的上拉刷新
//我就省略不写了。。。。。。。
}
/**
* 下拉拉刷新
*/
- (void)setFooterRefreshView{
//这里要父类中实现具体的下拉刷新
//我就省略不写了。。。。。。。
}
/**
* 注册cell
*/
- (void)setupRegisterCellClasses:(NSArray *)registerCellClasses{
_registerCellClasses = registerCellClasses;
//注册cell
for (Class objClass in registerCellClasses) {
if ([objClass isSubclassOfClass:[UITableViewCell class]]) {
[self.tableView registerClass:objClass forCellReuseIdentifier:NSStringFromClass(objClass)];
}
}
}
@end
二.模板方法的使用
声明:
#import "MYTableViewVC.h"
@interface MYSubTableViewVC : MYTableViewVC
@end
实现:
#import "MYSubTableViewVC.h"
@interface MYSubTableViewVC ()
@end
@implementation MYSubTableViewVC
- (void)viewDidLoad {
[super viewDidLoad];
[self setupRegisterCellClasses:@[[UITableViewCell class]]];
}
/**
* “标准”算法,子类重载,也是模板方法模式的重点
* 数据请求
*/
- (void)requestDataSuccess:(void (^)(NSArray *dataArr))success failure:(void (^)(NSString *msg))failure{
//具体网络请求操作
//子类实现,父类调用
}
/**
* 模板方法中的钩子方法,默认是无操作的,也不可以不重写的,不对模板造成影响
*/
- (void)cellCallBack:(UITableViewCell *)cell indexPath:(NSIndexPath *)indexPath{
//可以什么也不操作,或不重写
}
@end
看完demo是不是觉得模板方法很简单呢?是的,我们平时的开发中经常用到它。我只是做了一下小结。其实开发中,我们必须要保证模板方法的正常工作,也要求子类必须进行重载。如果模板方法有几个,思考一下我们要怎样来确保它们都重载了呢?我们可以采用简单粗爆的方法来调试代码,那就是在要重载的模式方法中抛出异常语句即可。如下:
/**
* “标准”算法,子类重载
* 数据请求
*/
- (void)requestDataSuccess:(void (^)(NSArray *dataArr))success failure:(void (^)(NSString *msg))failure{
[NSException raise:NSInternalInconsistencyException format:@"you must override %@ in a subclass",NSStringFromSelector(_cmd)];
}
我只是针对我平时项目开发中的一些小结,有不对、不到位或片面的,欢迎指出。觉得有帮助,请start一个吧。如要转载,请求标明出处,谢谢。