模版方法模式:在一个方法中定义算法的骨架。而将一些具体的步骤延续到子类中。模版方法模式让子类在不改变算法逻辑的基础上可以重新定义算法的某些步骤。
模版方法模式简称为模版模式是行为性模式之一。看定义我们大概可以知道的是,模版方法模式提供一个算法的骨架,也就是模版方法。而算法的某些关键性的步骤由子类具体实现。以此来提高系统的灵活性。
模版方法的强大之处在于其一通过模版方法,将部分关键性的算法放到子类来实现,提高系统的灵活性,其二是可以很方便的提供钩子。
钩子是声明在抽象类中的方法,但只有空的/默认的实现。钩子的存在可以让子类有能力对算法的不同点进行挂钩。
举个栗子
比如说我们开了一家饮料店。
整体上讲茶,咖啡,还有其他的饮料的做法都是相似的。烧开水,浸泡饮料的响应成分(茶叶,咖啡,可可粉,奶茶粉等等),将饮料倒入杯中,加配料。
烧开水,将饮料倒入杯中是固定的写法,没有其他可操作的成分。
浸泡饮料涉及到具体的饮品。所以需要在子类中实现。
加配料是可选的。有的顾客想要加,有的顾客不想加。
所以钩子可以加在配料哪里。
如果实现了钩子,说明是需要加配料的,如果没有实现钩子,说明不需要加配料。
饮料抽象类 这里preapreRecipe 就是模版方法。isAddingComditions方法是钩子方法。
#import "CaffineBaverate.h"
@implementation CaffineBaverate
//模版方法
-(void)preapreRecipe {
[self boilWater];
[self brew];
[self pureInCup];
if ([self isAddingComditions]) {
[self addComditions];
}
}
-(void)boilWater {
NSLog(@"烧开水");
}
-(void)pureInCup {
NSLog(@"放入杯中");
}
- (void)brew {
@throw [NSException exceptionWithName:@"抽象类" reason:@"抽象类中的抽象方法由子类实现,不能直接调用抽象类" userInfo:nil];
}
-(void)addComditions {
@throw [NSException exceptionWithName:@"抽象类" reason:@"抽象类中的抽象方法由子类实现,不能直接调用抽象类" userInfo:nil];
}
-(BOOL)isAddingComditions {
return YES;
}
@end
具体饮料茶(继承于抽象饮料)
#import "Tea.h"
@interface Tea ()
@property (nonatomic ,strong)NSString * text;
@end
@implementation Tea
-(void)brew {
NSLog(@"浸泡茶叶");
}
-(void)addComditions {
NSLog(@"给茶添加冰和冰糖");
}
//实现了钩子
- (BOOL)isAddingComditions {
char cString[10];
printf("需要添加点配料吗(输入y/n):");
scanf("%s",cString);
if ([[NSString stringWithCString:cString encoding:NSUTF8StringEncoding] containsString:@"y"]) {
return true;
}
return false;
}
@end
具体的使用
Tea * tea = [[Tea alloc] init];
//preapreRecipe是抽象类中的算法骨架,该算法中的brew和addComditions延迟到Tea中实现。
[tea preapreRecipe];
模版方法模式也有其他形式的变体。
举个栗子
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol Comparable <NSObject>
-(BOOL)compareTo:(id<Comparable>)obj;
@end
NS_ASSUME_NONNULL_END
这是一个数组的排序类(这里将compareTo方法在子类实现)
#import "NSObject+sort.h"
@implementation NSObject (sort)
+(NSMutableArray *)sortWithArray:(NSMutableArray<Comparable> *)sortArray {
sortArray = [sortArray mutableCopy];
for (int i = 0; i<= sortArray.count - 1; i++) {
for (int j = i ; j >= 1 ; j --) {
if ([sortArray[j - 1] compareTo:sortArray[j]]) {
[sortArray exchangeObjectAtIndex:j withObjectAtIndex:j-1];
}
}
}
return sortArray;
}
@end
这是具体类
#import "IDCard.h"
@implementation IDCard
-(BOOL)compareTo:(IDCard *)obj {
if (self.idString.length != 18) exit(0) ;
if (obj.idString.length != 18) exit(0) ;
int year = [[self.idString substringWithRange:NSMakeRange(6, 4)] intValue];
int comYear = [[obj.idString substringWithRange:NSMakeRange(6, 4)] intValue];
if (year < comYear) {
return YES;
}else if (year == comYear)
{
int month = [[self.idString substringWithRange:NSMakeRange(10, 2)] intValue];
int comMonth = [[obj.idString substringWithRange:NSMakeRange(10, 2)] intValue];
if (month < comMonth) {
return YES;
}else if (month == comMonth) {
int day = [[self.idString substringWithRange:NSMakeRange(12, 2)] intValue];
int comDay = [[obj.idString substringWithRange:NSMakeRange(12, 2)] intValue];
if (day < comDay) {
return YES;
}else {
return NO;
}
}
}
return NO;
}
-(NSString *)description {
return self.idString;
}
@end
这个模式意在提供一个算法骨架,而子类去实现其中的某些步骤,而这里的排序却并非如此。但是这里的实现却符合模版方法模式的精神,亦算作模版方法模式。
优点
提升了代码的灵活性
增强了复用性
能很好的添加钩子,监听或者管理方法的调用
缺点
算法骨架不容易修改,违背开闭原则。