你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS運用應用設計形式中的Strategy戰略形式的開辟實例

iOS運用應用設計形式中的Strategy戰略形式的開辟實例

編輯:IOS開發綜合

  在寫法式的時刻,我們常常會碰著如許的場景:把一堆算法塞到統一段代碼中,然後應用if-else或switch-case前提語句來決議要應用哪一個算法?這些算法能夠是一堆類似的類函數或辦法,用以處理相干的成績。好比,一個驗證輸出數據的例程,數據自己可所以任何數據類型(如NSString、CGFloat等),每種數據類型須要分歧的驗證算法。假如能把每一個算法封裝成一個對象,那末就可以清除依據數據類型決議應用甚麼算法的一堆if-else或switch-case語句。


    我們把相干算法分別為分歧的類,稱為戰略形式。戰略形式:界說一系列算法,把它們一個個封裝起來,而且使它們可互相調換。本形式使得算法可自力於應用它的客戶端而變更。

    在以下情況下,我們應當斟酌應用戰略形式。
    @:一個類在其操作中,應用多個前提語句來界說很多行動,我們可以把相干的前提分支移到它們本身的戰略類中。
    @:須要算法的各類變體。
    @:須要防止把龐雜的、與算法相干的數據構造暴漏給客戶端。

    我們用一個簡略的例子來講明以下,戰略形式是怎樣應用的。假定有兩個UITextField,一個UITextField只能輸出字母,另外一個UITextField只能輸出數字,為了確保輸出的有用性,我們須要在用戶停止文本框的編纂時做下驗證。我們把數據驗證放在署理辦法textFieldDidEndEdting中。

    假如不應用戰略形式,我們的代碼會寫成如許:

- (void)textFieldDidEndEditing:(UITextField *)textField {
    if (textField == self.numberTF) {
        // 驗證其值只包括數字
       
    }else if (textField == self.alphaTF) {
        // 驗證其值只包括字母
       
    }
}

    如果有更多分歧類型的文本框,前提語句還會持續下去。假如能去失落這些前提語句,代碼會更輕易治理,未來對代碼的保護也會輕易很多。

    如今的目的是把這些驗證檢討提到各類戰略類中,如許他們就可以在署理辦法和其他辦法當中重用。每一個驗證都從文本框掏出輸出值,然後依據所H需的戰略停止驗證,最初前往一個BOOL值。假如前往掉敗,還會前往一個NSError實例。前往的NSError可以說明掉敗的緣由。

    我們設計一個籠統基類InputValidator,外面有一個validateInput:input error:error辦法。分離有兩個子類NumberInputValidator、AlphaInputValidator。詳細的代碼以下所示:

    InputValidator.h中籠統InputValidator的類聲明

static NSString *const InputValidationErrorDomain = @"InputValidationErrorDomain";
 
@interface InputValidator : NSObject
/**
 *  現實驗證戰略的存根辦法
 */
- (BOOL)validateInput:(UITextField *)input error:(NSError *__autoreleasing *)error;
 
@end

    這個辦法還有一個NSError指針的援用,當有毛病產生時(即驗證掉敗),辦法會結構一個NSError實例,並賦值給這個指針,如許應用驗證的處所就可以做具體的毛病處置。

    InputValidator.m中籠統InputValidator的默許完成

#import "InputValidator.h"
 
@implementation InputValidator
 
- (BOOL)validateInput:(UITextField *)input error:(NSError *__autoreleasing *)error {
    if (error) {
        *error = nil;
    }
    return NO;
}
 
@end

    我們曾經界說了輸出驗證器的行動,然後我們要編寫真實的輸出驗證器了,先來寫數值型的,以下:

    NumberInputValidator.h中NumberInputValidator的類界說

#import "InputValidator.h"
 
@interface NumberInputValidator : InputValidator
 
/**
 *  這裡從新聲清楚明了這個辦法,以強調這個子類完成或重載了甚麼,這不是必需的,然則是個好習氣。
 */
- (BOOL)validateInput:(UITextField *)input error:(NSError *__autoreleasing *)error;
@end

    NumberInputValidator.m中NumberInputValidator的完成

#import "NumberInputValidator.h"
 
@implementation NumberInputValidator
 
- (BOOL)validateInput:(UITextField *)input error:(NSError *__autoreleasing *)error {
    NSError *regError = nil;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[0-9]*$" options:NSRegularExpressionAnchorsMatchLines error:®Error];
    
    NSUInteger numberOfMatches = [regex numberOfMatchesInString:input.text options:NSMatchingAnchored range:NSMakeRange(0, input.text.length)];
    // 假如沒有婚配,就會毛病和NO.
    if (numberOfMatches == 0) {
        if (error != nil) {
            // 先斷定error對象是存在的
            NSString *description = NSLocalizedString(@"驗證掉敗", @"");
            NSString *reason = NSLocalizedString(@"輸出僅能包括數字", @"");
            NSArray *objArray = [NSArray arrayWithObjects:description, reason, nil];
            NSArray *keyArray = [NSArray arrayWithObjects:NSLocalizedDescriptionKey, NSLocalizedFailureReasonErrorKey, nil];
            
            NSDictionary *userInfo = [NSDictionary dictionaryWithObjects:objArray forKeys:keyArray];
            //毛病被聯系關系到定制的毛病代碼1001和在InputValidator的頭文件中。
            *error = [NSError errorWithDomain:InputValidationErrorDomain code:1001 userInfo:userInfo];
        }
        
        return NO;
    }
    
    return YES;
}
 
@end

    如今,我們來編寫字母驗證的完成,代碼以下:

    AlphaInputValidator.h中AlphaInputValidator的類界說

#import "InputValidator.h"
@interface AlphaInputValidator : InputValidator
 
- (BOOL)validateInput:(UITextField *)input error:(NSError *__autoreleasing *)error;
 
@end

    AlphaInputValidator.m中AlphaInputValidator的完成:

#import "AlphaInputValidator.h"
 
@implementation AlphaInputValidator
 
- (BOOL)validateInput:(UITextField *)input error:(NSError *__autoreleasing *)error {
    NSError *regError = nil;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[a-zA-Z]*$" options:NSRegularExpressionAnchorsMatchLines error:®Error];
    
    NSUInteger numberOfMatches = [regex numberOfMatchesInString:input.text options:NSMatchingAnchored range:NSMakeRange(0, input.text.length)];
    // 假如沒有婚配,就會毛病和NO.
    if (numberOfMatches == 0) {
        if (error != nil) {
            // 先斷定error對象是存在的
            NSString *description = NSLocalizedString(@"驗證掉敗", @"");
            NSString *reason = NSLocalizedString(@"輸出僅能包字母", @"");
            NSArray *objArray = [NSArray arrayWithObjects:description, reason, nil];
            NSArray *keyArray = [NSArray arrayWithObjects:NSLocalizedDescriptionKey, NSLocalizedFailureReasonErrorKey, nil];
            
            NSDictionary *userInfo = [NSDictionary dictionaryWithObjects:objArray forKeys:keyArray];
            *error = [NSError errorWithDomain:InputValidationErrorDomain code:1002 userInfo:userInfo]; //毛病被聯系關系到定制的毛病代碼1002和在InputValidator的頭文件中。
        }
        
        return NO;
    }
    
    return YES;
}
 
@end

    AlphaInputValidator也是完成了validateInput辦法的InputValidator類型。它的代碼構造和算法跟NumberInputValidator類似,只是應用了分歧的正則表達式,分歧毛病代碼和新聞。可以看到兩個版本的代碼有許多反復。兩個算法構造雷同,我們可以把這個構造,我們可以把這個構造重組成籠統父類的模板辦法(將鄙人一篇博客中,來停止完成)。

    至此,我們曾經寫好了輸出驗證器,可以在客戶端來應用了,然則UITextField不熟悉它們,所以我們須要本身的UITextField版本。我們要創立UITextField的子類,個中有一個InputValidator的援用,和一個辦法validate。代碼以下:

CustomTextField.h中CustomTextField的類聲明

#import <UIKit/UIKit.h>
#import "InputValidator.h"
@interface CustomTextField : UITextField
 
@property (nonatomic, strong) InputValidator *inputValidator; //用一個屬性堅持對InputValidator的援用。
 
- (BOOL)validate;
 
@end

    CustomTextField有一個屬性堅持著對InputValidator的援用。當挪用它的validate辦法時,它會應用這個InputValidator援用,開端停止現實的驗證進程。

    CustomTextField.m中CustomTextField的完成

#import "CustomTextField.h"
 
@implementation CustomTextField
 
- (BOOL)validate {
    NSError *error = nil;
    BOOL validationResult = [_inputValidator validateInput:self error:&error];
    
    if (!validationResult) {
        // 經由過程這個例子也讓本身明確了,NSError的詳細用法。
        UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:[error localizedDescription] message:[error localizedFailureReason] delegate:nil cancelButtonTitle:@"肯定" otherButtonTitles:nil, nil];
        [alertView show];
    }
    
    return validationResult;
}
 
@end

    validate辦法向inputValidator援用發送了[_inputValidator validateInput:self error:&error]新聞。CustomTextField無需曉得應用的是甚麼類型的InputValidator和算法的任何細節,這就是戰略形式的利益。關於客戶端應用來講,只須要挪用validate辦法便可以了。是以在未來假如添加了新的InputValidator,客戶端不須要做任何的修改的。

    上面,我們看下客戶端是怎樣應用的,代碼以下。

#import "ViewController.h"
#import "CustomTextField.h"
#import "InputValidator.h"
#import "NumberInputValidator.h"
#import "AlphaInputValidator.h"
@interface ViewController () <UITextFieldDelegate>
 
@property (weak, nonatomic) IBOutlet CustomTextField *numberTF;
@property (weak, nonatomic) IBOutlet CustomTextField *alphaTF;
 
 
@end
 
@implementation ViewController
 
- (void)viewDidLoad {
    [super viewDidLoad];
    
    InputValidator *numberValidator = [[NumberInputValidator alloc] init];
    InputValidator *alphaValidator = [[AlphaInputValidator alloc] init];
    
    _numberTF.inputValidator = numberValidator;
    _alphaTF.inputValidator = alphaValidator;
}
 
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
 
#pragma mark - UITextFieldDelegate
 
- (void)textFieldDidEndEditing:(UITextField *)textField {
    if ([textField isKindOfClass:[CustomTextField class]]) {
        [(CustomTextField *)textField validate];
    }
}
 
@end

    可以看出,我們不須要那些前提語句了,相反,我們應用一條簡練很多的語句,完成異樣的數據驗證。除下面多了一條確保textField對象的類型是CustomField的額定檢討以外,不該再有任何龐雜的器械。

Strategy形式有上面的一些長處:
1) 相干算法系列 Strategy類條理為Context界說了一系列的可供重用的算法或行動。 繼續有助於析掏出這些算法中的公共功效。
2) 供給了可以調換繼續關系的方法: 繼續供給了另外一種支撐多種算法或行動的辦法。你可以直接生成一個Context類的子類,從而給它以分歧的行動。但這會將行動硬行編制到 Context中,而將算法的完成與Context的完成混雜起來,從而使Context難以懂得、難以保護和難以擴大,並且還不克不及靜態地轉變算法。最初你獲得一堆相干的類 , 它們之間的獨一差異是它們所應用的算法或行動。 將算法封裝在自力的Strategy類中使得你可以自力於其Context轉變它,使它易於切換、易於懂得、易於擴大。
3) 清除了一些if else前提語句 :Strategy形式供給了用前提語句選擇所需的行動之外的另外一種選擇。當分歧的行動堆砌在一個類中時 ,很難防止應用前提語句來選擇適合的行動。將行動封裝在一個個自力的Strategy類中清除了這些前提語句。含有很多前提語句的代碼平日意味著須要應用Strategy形式。
4) 完成的選擇 Strategy形式可以供給雷同行動的分歧完成。客戶可以依據分歧時光 /空間衡量棄取請求從分歧戰略中停止選擇。

Strategy形式缺陷:

1)客戶端必需曉得一切的戰略類,並自行決議應用哪個戰略類: 本形式有一個潛伏的缺陷,就是一個客戶要選擇一個適合的Strategy就必需曉得這些Strategy究竟有何分歧。此時能夠不能不向客戶裸露詳細的完成成績。是以僅當這些分歧行動變體與客戶相干的行動時 , 才須要應用Strategy形式。
2 ) Strategy和Context之間的通訊開支 :不管各個ConcreteStrategy完成的算法是簡略照樣龐雜, 它們都同享Strategy界說的接口。是以極可能某些 ConcreteStrategy不會都用到一切經由過程這個接口授遞給它們的信息;簡略的 ConcreteStrategy能夠不應用個中的任何信息!這就意味著有時Context會創立和初始化一些永久不會用到的參數。假如存在如許成績 , 那末將須要在Strategy和Context之間更停止慎密的耦合。
3 )戰略形式將形成發生許多戰略類:可以經由過程應用享元形式在必定水平上削減對象的數目。 增長了對象的數量 Strategy增長了一個運用中的對象的數量。有時你可以將 Strategy完成為可供各Context同享的無狀況的對象來削減這一開支。任何其他的狀況都由 Context保護。Context在每次對Strategy對象的要求中都將這個狀況傳遞曩昔。同享的 Strategy不該在各次挪用之間保護狀況。

【iOS運用應用設計形式中的Strategy戰略形式的開辟實例】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved