策略模式的定义,《HeadFirst》这本书,定的比较详细,此文不作过多描述。
对于策略模式,将从下面几个方面进行分析:
方面一:策略模式和适用的场景。
1.类中定义了很多条件判断语句来进行不同的选择。
2.不想把类中的具体细节,数据结构暴露给调用者。
这种说法好似放之四海而皆准,太过朦胧,有点雾里看花。下面使用一个常见的例子来说明。
以生活中面试为例:一个公司有不同的岗位(Cocos2d手游、Python 、ai工程师、设计),有A,B ,C,D
等应聘者前来面试不同的工作岗位。这个公司有个规定,需要应聘者做相应的笔试题目。
如果不用策略模式实现的话可能会写成这样:
if "Cocos2d手游":
做 Cocos2d手游 题目
else if "Python":
做 python 题目:
这种情况 如果条件语句比较少的话,没什么问题 ,但是在更新的时候可能就比较烦了,需要扩展这个条件判断语句
即把自己的条件语句加到上面这段代码中。这对于代码设计而言对于结构不太友好,且对于过多的条件语句,难以维护。而策略模式,生就是为了解决这种问题的。
方面二:策略模式类的角色分析。
角色一:抽象策略基类,这个类是用来封装规范接口的,对于策略执行者而言它是不知道具体的策略内容的。
在整个模式中,担任2个角色:保持具体策略的引用,规范接口。
角色二:具体的策略类,这个类需要扩展抽象策略基类,统一规范接口。方便使用基类引用时进行调用。
在上面的例子中可理解为:不同的岗位(Cocos2d手游、Python 、ai工程师、设计)对应的笔试题目。
角色三:策略选择器,由谁来分发策略。上面的例子中,这个角色一般由HR来担任。很明显,HR需要知道策略(具体的策略内容可以不知道),然后根据不同的应聘者选择不同的笔试题目。
下面根据这三个角色来进行笔试题目分发:
抽象基类:
#import <Foundation/Foundation.h>
/**
策略基类,规范策略执行的接口,具体的策略由各自的策略对象去执行
*/
@interface StrategyBase : NSObject
/**
执行策略
*/
-(void) executeStrategy;
@end
。m文件:
#import "StrategyBase.h"
@implementation StrategyBase
-(void) executeStrategy{
NSLog(@"如果不定义具体的策略,我就执行默认的策略");
}
@end
具体的策略类:这里只用Cocos2d 与python为例:
Cocos2dStrategy.h:
#import <Foundation/Foundation.h>
#import "StrategyBase.h"
@interface Cocos2dStrategy : StrategyBase
//重载基类的 执行策略接口,可以不必在头文件中进行声明,这样写只是为了规范
-(void) executeStrategy;
@end
.m文件:
#import "Cocos2dStrategy.h"
@implementation Cocos2dStrategy
-(void) executeStrategy{
NSLog(@"cocos2d 岗位需要,选择这里的策略");
}
@end
同理python。h文件为:
#import <Foundation/Foundation.h>
#import "StrategyBase.h"
@interface PythonStrategy : StrategyBase
-(void)executeStrategy;
@end
#import "PythonStrategy.h"
@implementation PythonStrategy
-(void) executeStrategy{
NSLog(@"Python 岗位,选择这这里的策略");
}
@end
策略选择器,也即为HR扮演的角色:
#import <Foundation/Foundation.h>
#import "StrategyBase.h"
/**
策略选择器,负责选择具体的策略
因为具体的策略,在客户端选择之前是未定的,所以需要用策略基类来保持具体的策略的引用
*/
@interface StrategySelecter : NSObject
/**
策略引用保持者
*/
@property(nonatomic,retain) StrategyBase* strategy;
+(instancetype) getInstance;
/**
选择策略
@param strategy 具体的策略对象
*/
-(void) selectStrategy:(StrategyBase*) strategy;
/**
执行策略 这个方法其实可以省略,为了方便阅读,与解偶合执行的动作放在这里
*/
-(void) executeStrategy;
@end
//
// StrategySelecter.m
// DesignPattern
//
// Created by 刘小兵 on 2017/7/21.
// Copyright © 2017年 刘小兵. All rights reserved.
//
#import "StrategySelecter.h"
static StrategySelecter* strategyInstance = nil;
@implementation StrategySelecter
+(instancetype) getInstance{
@synchronized (self) {
if(strategyInstance == nil){
strategyInstance = [[StrategySelecter alloc] init];
}
}
return strategyInstance;
}
-(void) selectStrategy:(StrategyBase*) strategy{
self.strategy = strategy;
//高手一般都能看出来,策略选择器中的那个基类策略引用保持者,只 是为了代码的扩展性,如果没有那个引用
// [strategy executeStrategy ];
}
-(void) executeStrategy{
if(self.strategy){
[self.strategy executeStrategy];
}
}
@end
StrategySelecter* selector = [StrategySelecter getInstance];
Cocos2dStrategy* cocos2d = [[Cocos2dStrategy alloc] init];
[selector selectStrategy:cocos2d];
[selector selectStrategy:[[PythonStrategy alloc] init]];
测试结果: