- if - else 的問題
- 策略模式的原理
- 策略模式的使用
- 策略模式的優(yōu)缺點(diǎn)
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判斷特別多的時(shí)候,代碼邏輯就復(fù)雜了培慌,可讀性也很差。
也許我們會(huì)把這些判斷單獨(dú)放到一個(gè)類里面來進(jìn)行處理哈肖。
#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
這樣抽離出來一個(gè)類瘦锹,我們需要用到的時(shí)候只要調(diào)用這個(gè)類的一個(gè)方法就可以了脆贵,但實(shí)際上在這個(gè)類的方法中残家,依然還是通過if-else判斷泣港,代碼量并沒有減少兽间,邏輯也沒有簡(jiǎn)化历葛,知識(shí)挪了一下位置而已.
策略模式的原理
定義一系列的算法,把每一個(gè)算法封裝起來, 并且使它們可相互替換。本模式使得算法可獨(dú)立于使用它的客戶而變化嘀略。
*相同的輸入不同的輸出
下面是一個(gè)策略模式的具體實(shí)現(xiàn)恤溶,下面我們要做的是一個(gè)表單的輸入驗(yàn)證。
我們自定義的一個(gè)文本輸入CustomField
#import <UIKit/UIKit.h>
#import "InputValidator.h"
@interface CustomField : UITextField
/**
* 抽象的策略
*/
@property (nonatomic, strong) InputValidator *validator;
/**
* 初始化textField
*
* @param frame
* @param inputValidator 驗(yàn)證策略
*
* @return 實(shí)例對(duì)象
*/
- (instancetype)initWithFrame:(CGRect)frame;
/**
* 驗(yàn)證輸入合法性
*
* @return 是否合法,不合法,讀取InputValidator當(dāng)中的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
下面我們接著定義一個(gè)抽象的策略類:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface InputValidator : NSObject
/**
* 策略的輸入
*
* @param input
*
* @return 如果為YES,表示測(cè)試通過,如果為NO,表示測(cè)試不通過
*/
- (BOOL)validateInput:(UITextField *)input;
/**
* 當(dāng)validateInput為NO的時(shí)候,我們來讀取errorMessage
*/
@property (nonatomic, strong) NSString *errorMessage;
@end
#import "InputValidator.h"
@implementation InputValidator
- (BOOL)validateInput:(UITextField *)input {
return NO;
}
@end
最后我們?cè)賹?shí)現(xiàn)具體的策略類帜羊,在此我們實(shí)現(xiàn)兩個(gè)策略類咒程,一個(gè)是電話驗(yàn)證,一個(gè)是email驗(yàn)證讼育。
#import "InputValidator.h"
@interface PhoneNumberValidator : InputValidator
/**
* 重載了父類的驗(yàn)證方法
*/
- (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 = @"請(qǐng)輸入正確的手機(jī)號(hào)碼";
} else {
self.errorMessage = nil;
}
}
return self.errorMessage == nil ? YES : NO;
}
@end
#import "InputValidator.h"
@interface EmailValidator : InputValidator
/**
* 重載了父類的驗(yàn)證方法
*/
- (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 = @"請(qǐng)輸入正確的郵箱";
} 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>
/**
* 輸入郵箱的驗(yàn)證框
*/
@property (nonatomic, strong) CustomField *emailField;
/**
* 輸入電話號(hào)碼的驗(yàn)證框
*/
@property (nonatomic, strong) CustomField *phoneNumberField;
/**
* 驗(yàn)證email地址
*
* @param input 輸入
*
* @return 輸出結(jié)果
*/
- (NSString *)validateEmailInput:(UITextField *)input;
/**
* 驗(yàn)證電話號(hào)碼
*
* @param input 輸入
*
* @return 輸出結(jié)果
*/
- (NSString *)validatePhoneNumberInput:(UITextField *)input;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化按鈕
[self initButton];
// 初始化驗(yàn)證框
[self initCustomFields];
}
#pragma mark - 初始化文本輸入框
- (void)initCustomFields {
self.emailField = [[CustomField alloc] initWithFrame:CGRectMake(30, 80, Width - 60, 30)];
self.emailField.placeholder = @"請(qǐng)輸入郵箱";
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 = @"請(qǐng)輸入電話號(hào)碼";
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
假如我們已有的代碼不能修改了帐姻,我們要驗(yàn)證一下郵編時(shí)我們只需要添加一個(gè)郵編驗(yàn)證的策略類就行了。你看看是不是很方便呢奶段。
策略模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):可以將if-else這樣的判斷代碼精簡(jiǎn)成一行代碼饥瓷。
策略模式提供了對(duì)開放—封閉原則的完美支持,將算法封裝在獨(dú)立的strategy中痹籍,使得它們易于切換呢铆,易于理解,易于擴(kuò)展蹲缠。
策略模式中的算法也可以復(fù)用在系統(tǒng)的其他地方棺克,從而避免許多重復(fù)的復(fù)制粘貼工作鳖宾。
在策略模式中利用組合和委托來讓Context擁有執(zhí)行算法的能力,這也是繼承的一種更輕便的替代方案逆航。
缺點(diǎn):要使用策略模式鼎文,必須了解所有的strategy,必須了解各個(gè)strategy之間的不同點(diǎn)因俐,這樣才能選擇一個(gè)合適的strategy拇惋。比如,我們要選擇一種合適的旅游出行路線抹剩,必須先了解選擇飛機(jī)撑帖、火車、自行車等方案的細(xì)節(jié)澳眷。此時(shí)strategy要向客戶暴露它的所有實(shí)現(xiàn)胡嘿,這是違反最少知識(shí)原則的。使用策略模式的前提是要明確知道每個(gè)策略的細(xì)節(jié)钳踊。