什么是策略设计模式?
概念:定义一系列的算法,并且将每个算法封装起来,算法之间还可以互相替换。这种设计模式称为策略模式。
为了解决if-else和switch-case的问题,在实际开发中,较长的if-else会使代码阅读困难。
代码示例:下面是一个简单的if-else代码
Demo1
#import "ViewController.h"
typedef NS_ENUM(NSInteger) {
Count01,
Count02,
Count03,
Count04,
Count05,
}EnumCount;
@interface ViewController ()
@end
@implementation ViewController
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
EnumCount count = Count04;//声明枚举,并给了一个固定的输入值
if (count == 1) {
NSLog(@"count = %lu",count);
} else if (count == 2) {
NSLog(@"count = %lu",count);
}else if (count == 3) {
NSLog(@"count = %lu",count);
}else if (count == 4) {
NSLog(@"count = %lu",count);
} else {
NSLog(@"count = %lu",count);
}
}
@end
我们使用正常的代码抽离方式对其优化分离。
创建一个NSObject的类,Logic
Logic.h
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger) {
Count01,
Count02,
Count03,
Count04,
Count05,
}EnumCount;
@interface Logic : NSObject
+ (NSUInteger)logic:(NSUInteger)integer;
@end
Logic.m
#import "Logic.h"
@implementation Logic
+ (NSUInteger)logic:(NSUInteger)integer {
NSUInteger num;
if (integer == 1) {
num = 1;
} else if (integer == 2) {
num = 2;
}else if (integer == 3) {
num = 3;
}else if (integer == 4) {
num = 4;
} else {
num = 0;
}
return num;
}
@end
那么修改ViewController如下
#import "ViewController.h"
#import "Logic.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
EnumCount count = Count04;
NSUInteger integer = [Logic logic:count];
NSLog(@"integer = %lu", integer);
}
@end
那么如何使用策略模式呢?
新建继承自NSObject 的 BaseType类
BaseType.h文件
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger) {
Count01,
Count02,
Count03,
Count04,
Count05,
}EnumCount;
@interface BaseType : NSObject
//返回计数结果
+(NSUInteger)backCountResult;
@end
BaseType.m
#import "BaseType.h"
@implementation BaseType
//抽象方法
+(NSUInteger)backCountResult {
//编写代码
return nil;
}
@end
创建继承自BaseType的子类CountTypes01
CountTypes01.h
#import "BaseType.h"
@interface CountTypes01 : BaseType
@end
CountTypes01.m
#import "CountTypes01.h"
@implementation CountTypes01
+ (NSUInteger)backCountResult {
// 编写代码
return 10;
}
@end
那么修改ViewController如下
#import "ViewController.h"
#import "CountTypes01.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSUInteger integer = [CountTypes01 backCountResult];
NSLog(@"integer = %lu", integer);
}
@end
优缺点
策略模式的优点是能解决代码的耦合度,但是它是有牺牲的,为了解决代码耦合度,我们需要创建更多的类。
Demo2
需求:验证两个textField的输入条件
初始代码:
ViewController.m
#import "ViewController.h"
@interface ViewController () <UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet UITextField *letterInput; /**< 字母输入 */
@property (weak, nonatomic) IBOutlet UITextField *numberInput; /**< 数字输入 */
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.letterInput.delegate = self;
self.numberInput.delegate = self;
}
- (IBAction)btnClick:(id)sender {
[self.view endEditing:YES];
}
#pragma mark - UITextFieldDelegate
- (void)textFieldDidEndEditing:(UITextField *)textField {
if (textField == self.letterInput) {
// 验证它的输入值, 确保它输入的是字母
NSString *outputLatter = [self validateLatterInput:textField];
if (outputLatter) {
NSLog(@"---%@",outputLatter);
}else {
NSLog(@"---输入是空的");
}
} else if (textField == self.numberInput) {
// 验证它的输入值, 确保它输入的是数字
NSString *outputNumber = [self validateNumberInput:textField];
if (outputNumber) {
NSLog(@"---%@",outputNumber);
}else {
NSLog(@"---输入是空的");
}
}
}
#pragma mark - 验证输入
- (NSString *)validateLatterInput:(UITextField *)textField {
if (textField.text.length == 0) {
return nil;
}
// ^[a-zA-Z]*$ 从开头(^)到结尾($), 有效字符集([a-zA-Z])或者更多(*)个字符
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[a-zA-Z]*$" options:NSRegularExpressionAnchorsMatchLines error:nil];
//NSMatchingAnchored 从开始处就进行极限匹配
NSUInteger numberOfMatches = [regex numberOfMatchesInString:[textField text] options:NSMatchingAnchored range:NSMakeRange(0, [[textField text] length])];
NSString *outLatter = nil;
// 进行判断,匹配不符合表示0的话, 就走下面的逻辑
if (numberOfMatches == 0) {
outLatter = @"不全是字母, 输入有误,请重新输入";
} else {
outLatter = @"输入正确,全部是字母";
}
return outLatter;
}
- (NSString *)validateNumberInput:(UITextField *)textField {
if (textField.text.length == 0) {
return nil;
}
// ^[a-zA-Z]*$ 从开头(^)到结尾($), 有效字符集([a-zA-Z])或者更多(*)个字符
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[0-9]*$" options:NSRegularExpressionAnchorsMatchLines error:nil];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:[textField text] options:NSMatchingAnchored range:NSMakeRange(0, [[textField text] length])];
NSString *outLatter = nil;
// 进行判断,匹配不符合表示0的话, 就走下面的逻辑
if (numberOfMatches == 0) {
outLatter = @"不全是数字, 输入有误,请重新输入";
} else {
outLatter = @"输入正确,全部是数字";
}
return outLatter;
}
@end
我们知道,所有的设计模式都是为了代码解耦合所使用的,代价肯定是需要创建其他的类,将代码分离。
那么我们如何使用策略模式来优化代码呢?
首先我们创建一个继承自NSObject的抽象类:InputTextFieldValidate
InputTextFieldValidate.h
#import <UIKit/UIKit.h>
@interface InputTextFieldValidate : NSObject
// 策略输入 YES 表示测试通过.No 表示测试不通过
- (BOOL)validateInputTextField:(UITextField *)textField;
@property (nonatomic, copy) NSString *attributeInputStr; /**< 属性字符串 */
@end
InputTextFieldValidate.m
#import "InputTextFieldValidate.h"
@implementation InputTextFieldValidate
- (BOOL)validateInputTextField:(UITextField *)textField {
return NO;
}
@end
再次创建一个继承自InputTextFieldValidate的类:LatterTextFieldValidate
LatterTextFieldValidate.h
#import "InputTextFieldValidate.h"
@interface LatterTextFieldValidate : InputTextFieldValidate
@end
LatterTextFieldValidate.m
#import "LatterTextFieldValidate.h"
@implementation LatterTextFieldValidate
- (BOOL)validateInputTextField:(UITextField *)textField {
if (textField.text.length == 0) {
self.attributeInputStr = @"字母不能是空的";
return nil;
}
// ^[a-zA-Z]*$ 从开头(^)到结尾($), 有效字符集([a-zA-Z])或者更多(*)个字符
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[a-zA-Z]*$" options:NSRegularExpressionAnchorsMatchLines error:nil];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:[textField text] options:NSMatchingAnchored range:NSMakeRange(0, [[textField text] length])];
// NSString *outLatter = nil;
// 进行判断,匹配不符合表示0的话, 就走下面的逻辑
if (numberOfMatches == 0) {
self.attributeInputStr = @"不全是字母, 输入有误,请重新输入";
} else {
self.attributeInputStr = @"输入正取,全部是字母";
}
return self.attributeInputStr == nil ? YES : NO;
}
@end
再次创建一个继承自InputTextFieldValidate的类:NumberTextFieldValidate
NumberTextFieldValidate.h
#import "InputTextFieldValidate.h"
@interface NumberTextFieldValidate : InputTextFieldValidate
@end
NumberTextFieldValidate.m
#import "NumberTextFieldValidate.h"
@implementation NumberTextFieldValidate
- (BOOL)validateInputTextField:(UITextField *)textField {
if (textField.text.length == 0) {
self.attributeInputStr = @"数值不能是空的";
return nil;
}
// ^[a-zA-Z]*$ 从开头(^)到结尾($), 有效字符集([a-zA-Z])或者更多(*)个字符
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[0-9]*$" options:NSRegularExpressionAnchorsMatchLines error:nil];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:[textField text] options:NSMatchingAnchored range:NSMakeRange(0, [[textField text] length])];
// NSString *outLatter = nil;
// 进行判断,匹配不符合表示0的话, 就走下面的逻辑
if (numberOfMatches == 0) {
self.attributeInputStr = @"不全是数字, 输入有误,请重新输入";
} else {
self.attributeInputStr = @"输入数字,全部是字母";
}
return self.attributeInputStr == nil ? YES : NO;
}
@end
然后创建一个继承自UITextField的类:CustomTextField(自定义的TextField)
CustomTextField.h
#import <UIKit/UIKit.h>
#import "InputTextFieldValidate.h"
@interface CustomTextField : UITextField
// 抽象的策略
@property (nonatomic, strong) InputTextFieldValidate *inputValidate;
// 验证是否符合要求
- (BOOL)validate;
@end
CustomTextField.m
#import "CustomTextField.h"
@implementation CustomTextField
- (BOOL)validate {
BOOL result = [self.inputValidate validateInputTextField:self];
if (!result) {
NSLog(@"---%@",self.inputValidate.attributeInputStr);
}
return result;
}
@end
ViewController.m就简洁多了,修改如下:
#import "ViewController.h"
#import "CustomTextField.h"
#import "LatterTextFieldValidate.h"
#import "NumberTextFieldValidate.h"
@interface ViewController () <UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet CustomTextField *letterInput; /**< 字母输入 */
@property (weak, nonatomic) IBOutlet CustomTextField *numberInput; /**< 数字输入 */
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.letterInput.delegate = self;
self.numberInput.delegate = self;
// 初始化
self.letterInput.inputValidate = [LatterTextFieldValidate new];
self.numberInput.inputValidate = [NumberTextFieldValidate new];
}
- (IBAction)btnClick:(id)sender {
[self.view endEditing:YES];
}
#pragma mark - UITextFieldDelegate
- (void)textFieldDidEndEditing:(UITextField *)textField {
if ([textField isKindOfClass:[CustomTextField class]]) {
[(CustomTextField *)textField validate];
}
}
@end
优点:控制器代码简洁,分离代码复用性高,逻辑清晰,方便拓展。