- if - else 的问题
- 策略模式的原理
- 策略模式的使用
- 策略模式的优缺点
if-else的问题
#import "ViewController.h"
/**
条件列表
*/
typedef enum : NSUInteger {
EType_01,
EType_02,
EType_03,
EType_04,
EType_05,
EType_06,
EType_07,
EType_08,
EType_09,
} ETypes;
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 输入条件
ETypes type = EType_01;
// 输出条件
NSString *showString = nil;
if (type == EType_01) {
// showString = ...
} else if (type == EType_02) {
// showString = ...
} else if (type == EType_03) {
// showString = ...
} else if (type == EType_04) {
// showString = ...
} else if (type == EType_05) {
// showString = ...
} else if (type == EType_06) {
// showString = ...
} else if (type == EType_07) {
// showString = ...
} else if (type == EType_08) {
// showString = ...
} else if (type == EType_09) {
// showString = ...
} else {
showString = @"";
}
}
@end
if-else判断特别多的时候,代码逻辑就复杂了,可读性也很差。
也许我们会把这些判断单独放到一个类里面来进行处理。
#import <Foundation/Foundation.h>
typedef enum : NSUInteger {
EType_01,
EType_02,
EType_03,
EType_04,
EType_05,
EType_06,
EType_07,
EType_08,
EType_09,
} ETypes;
@interface EtypeValue : NSObject
+ (NSString *)type:(ETypes)type;
@end
#import "EtypeValue.h"
@implementation EtypeValue
+ (NSString *)type:(ETypes)type {
// 输出条件
NSString *showString = nil;
if (type == EType_01) {
// showString = ...
} else if (type == EType_02) {
// showString = ...
} else if (type == EType_03) {
// showString = ...
} else if (type == EType_04) {
// showString = ...
} else if (type == EType_05) {
// showString = ...
} else if (type == EType_06) {
// showString = ...
} else if (type == EType_07) {
// showString = ...
} else if (type == EType_08) {
// showString = ...
} else if (type == EType_09) {
// showString = ...
} else {
showString = @"";
}
return showString;
}
@end
这样抽离出来一个类,我们需要用到的时候只要调用这个类的一个方法就可以了,但实际上在这个类的方法中,依然还是通过if-else判断,代码量并没有减少,逻辑也没有简化,知识挪了一下位置而已.
策略模式的原理
定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
*相同的输入不同的输出
下面是一个策略模式的具体实现,下面我们要做的是一个表单的输入验证。
我们自定义的一个文本输入CustomField
#import <UIKit/UIKit.h>
#import "InputValidator.h"
@interface CustomField : UITextField
/**
* 抽象的策略
*/
@property (nonatomic, strong) InputValidator *validator;
/**
* 初始化textField
*
* @param frame
* @param inputValidator 验证策略
*
* @return 实例对象
*/
- (instancetype)initWithFrame:(CGRect)frame;
/**
* 验证输入合法性
*
* @return 是否合法,不合法,读取InputValidator当中的errorMessage
*/
- (BOOL)validate;
@end
#import "CustomField.h"
@interface CustomField ()
@end
@implementation CustomField
#pragma mark - 初始化
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (void)setup {
UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, self.frame.size.height)];
self.leftView = leftView;
self.leftViewMode = UITextFieldViewModeAlways;
self.font = [UIFont fontWithName:@"Avenir-Book" size:12.f];
self.layer.borderWidth = 0.5f;
}
- (BOOL)validate {
return [self.validator validateInput:self];
}
@end
下面我们接着定义一个抽象的策略类:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface InputValidator : NSObject
/**
* 策略的输入
*
* @param input
*
* @return 如果为YES,表示测试通过,如果为NO,表示测试不通过
*/
- (BOOL)validateInput:(UITextField *)input;
/**
* 当validateInput为NO的时候,我们来读取errorMessage
*/
@property (nonatomic, strong) NSString *errorMessage;
@end
#import "InputValidator.h"
@implementation InputValidator
- (BOOL)validateInput:(UITextField *)input {
return NO;
}
@end
最后我们再实现具体的策略类,在此我们实现两个策略类,一个是电话验证,一个是email验证。
#import "InputValidator.h"
@interface PhoneNumberValidator : InputValidator
/**
* 重载了父类的验证方法
*/
- (BOOL)validateInput:(UITextField *)input;
@end
#import "PhoneNumberValidator.h"
#import "RegExCategories.h"
@implementation PhoneNumberValidator
- (BOOL)validateInput:(UITextField *)input {
if (input.text.length <= 0) {
self.errorMessage = @"没有输入";
} else {
BOOL isMatch = [input.text isMatch:RX(@"^((13[0-9])|(15[^4,\\D])|(18[0,0-9]))\\d{8}$")];
if (isMatch == NO) {
self.errorMessage = @"请输入正确的手机号码";
} else {
self.errorMessage = nil;
}
}
return self.errorMessage == nil ? YES : NO;
}
@end
#import "InputValidator.h"
@interface EmailValidator : InputValidator
/**
* 重载了父类的验证方法
*/
- (BOOL)validateInput:(UITextField *)input;
@end
#import "EmailValidator.h"
#import "RegExCategories.h"
@implementation EmailValidator
- (BOOL)validateInput:(UITextField *)input {
if (input.text.length <= 0) {
self.errorMessage = @"没有输入";
} else {
BOOL isMatch = [input.text isMatch:RX(@"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}")];
if (isMatch == NO) {
self.errorMessage = @"请输入正确的邮箱";
} else {
self.errorMessage = nil;
}
}
return self.errorMessage == nil ? YES : NO;
}
@end
那么我们使用中就可以是这样的
#import "ViewController.h"
#import "UIButton+inits.h"
#import "CustomField.h"
#import "UIView+SetRect.h"
#import "RegExCategories.h"
#import "UIInfomationView.h"
#import "EmailValidator.h"
#import "PhoneNumberValidator.h"
@interface ViewController () <UITextFieldDelegate>
/**
* 输入邮箱的验证框
*/
@property (nonatomic, strong) CustomField *emailField;
/**
* 输入电话号码的验证框
*/
@property (nonatomic, strong) CustomField *phoneNumberField;
/**
* 验证email地址
*
* @param input 输入
*
* @return 输出结果
*/
- (NSString *)validateEmailInput:(UITextField *)input;
/**
* 验证电话号码
*
* @param input 输入
*
* @return 输出结果
*/
- (NSString *)validatePhoneNumberInput:(UITextField *)input;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化按钮
[self initButton];
// 初始化验证框
[self initCustomFields];
}
#pragma mark - 初始化文本输入框
- (void)initCustomFields {
self.emailField = [[CustomField alloc] initWithFrame:CGRectMake(30, 80, Width - 60, 30)];
self.emailField.placeholder = @"请输入邮箱";
self.emailField.delegate = self;
self.emailField.validator = [EmailValidator new];
[self.view addSubview:self.emailField];
self.phoneNumberField = [[CustomField alloc] initWithFrame:CGRectMake(30, 80 + 40, Width - 60, 30)];
self.phoneNumberField.placeholder = @"请输入电话号码";
self.phoneNumberField.delegate = self;
self.phoneNumberField.validator = [PhoneNumberValidator new];
[self.view addSubview:self.phoneNumberField];
}
#pragma mark - 初始化按钮以及按钮事件
- (void)initButton {
UIButton *button = [UIButton createButtonWithFrame:CGRectMake(30, 30, 90, 30)
buttonType:0
title:@"Back"
tag:0
target:self
action:@selector(buttonsEvent:)];
[self.view addSubview:button];
}
- (void)buttonsEvent:(UIButton *)button {
[self.view endEditing:YES];
}
#pragma mark - 文本框代理
- (void)textFieldDidEndEditing:(UITextField *)textField {
CustomField *customField = (CustomField *)textField;
if ([customField validate] == NO) {
[UIInfomationView showAlertViewWithTitle:nil
message:customField.validator.errorMessage
cancelButtonTitle:nil
otherButtonTitles:@[@"确定"]
clickAtIndex:^(NSInteger buttonIndex) {
}];
}
}
@end
假如我们已有的代码不能修改了,我们要验证一下邮编时我们只需要添加一个邮编验证的策略类就行了。你看看是不是很方便呢。
策略模式的优缺点
优点:可以将if-else这样的判断代码精简成一行代码。
策略模式提供了对开放—封闭原则的完美支持,将算法封装在独立的strategy中,使得它们易于切换,易于理解,易于扩展。
策略模式中的算法也可以复用在系统的其他地方,从而避免许多重复的复制粘贴工作。
在策略模式中利用组合和委托来让Context拥有执行算法的能力,这也是继承的一种更轻便的替代方案。
缺点:要使用策略模式,必须了解所有的strategy,必须了解各个strategy之间的不同点,这样才能选择一个合适的strategy。比如,我们要选择一种合适的旅游出行路线,必须先了解选择飞机、火车、自行车等方案的细节。此时strategy要向客户暴露它的所有实现,这是违反最少知识原则的。使用策略模式的前提是要明确知道每个策略的细节。