定义:
工厂模式的思想主要为:多个类似的子类继承同一个父类,对其父类中的变量进行操作;工厂类负责判断、控制哪个子类被执行,而工厂类调用子类完成后,返回的结果是该子类的父类,该父类中的变量已经被操作过了,访问该父类,得到我们想要的结果
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
1. 相似:
在模式结构上,两者很相似;
2.差别:
用途不一样
工厂是创建型模式,它的作用就是创建对象;
策略是行为型模式,它的作用是让一个对象在许多行为中选择一种行为;
关注点不一样
一个关注对象创建
一个关注行为的封装
解决不同的问题
工厂模式是创建型的设计模式,它接受指令,创建出符合要求的实例;它主要解决的是资源的统一分发,将对象的创建完全独立出来,让对象的创建和具体的使用客户无关。主要应用在多数据库选择,类库文件加载等。
策略模式是为了解决的是策略的切换与扩展,更简洁的说是定义策略族,分别封装起来,让他们之间可以相互替换,策略模式让策略的变化独立于使用策略的客户。
工厂相当于黑盒子,策略相当于白盒子;
策略模式例子
例1、
(1)策略模式的核心就是对算法变化的封装。
定义一个通用算法协议,让每个算法遵守其规则。
@protocol LHPlayerProtocol <NSObject>
/**
* Player开启视频
*
* @return 描述(只为举例需要)
*/
- (NSString *)lh_play;
/**
* Player暂停视频
*
* @return 描述(只为举例需要)
*/
- (NSString *)lh_pause;
/**
* Player停止播放
*
* @return 描述(只为举例需要)
*/
- (NSString *)lh_stop;
AVPlayer的算法封装
#import <Foundation/Foundation.h>
#import "LHPlayerProtocol.h"
@interface LHAVPlayer : NSObject<LHPlayerProtocol>
@end
#import "LHAVPlayer.h"
#import "AVPlayer.h"
@interface LHAVPlayer ()
{
id<AVPlayerProtocol> player;// AVPlayer播放器自身的协议
}
@end
@implementation LHAVPlayer
- (instancetype)init
{
self = [super init];
if (self) {
player = [[AVPlayer alloc] init];// 初始化AVPlayer播放器对象
}
return self;
}
// 播放
- (NSString *)lh_play{
return [player a_play];
}
// 暂停
- (NSString *)lh_pause{
return [player a_pause];
}
// 停止
- (NSString *)lh_stop{
return [player a_stop];
}
- (void)dealloc
{
player = nil;
}
@end
View Code
IJKPlayer的算法封装
#import <Foundation/Foundation.h>
#import "LHPlayerProtocol.h"
@interface LHIJKPlayer : NSObject<LHPlayerProtocol>
@end
#import "LHIJKPlayer.h"
#import "Ijkplayer.h"
@interface LHIJKPlayer ()
{
id<IjkplayerProtocol> player;// IJKPlayer播放器自身的协议
}
@end
@implementation LHIJKPlayer
- (instancetype)init
{
self = [super init];
if (self) {
player = [[Ijkplayer alloc] init];// 初始化IJKPlayer播放器对象
}
return self;
}
// 播放
- (NSString *)lh_play{
return [player i_play];
}
// 暂停
- (NSString *)lh_pause{
return [player i_pause];
}
// 停止
- (NSString *)lh_stop{
return [player i_stop];
}
- (void)dealloc
{
player = nil;
}
@end
View Code
(2)策略模式中另一个核心类Context的定义
通用播放器类LHPlayer的定义。根据不同的策略选择不同的算法。
#import <Foundation/Foundation.h>
#import "LHPlayerProtocol.h"
// 播放器的类型
typedef enum : NSUInteger {
EPlayerType_AVPlayer,
EPlayerType_IJKPlayer
} EPlayerType;
@interface LHPlayer : NSObject
- (instancetype)initWithType:(EPlayerType)type;
/**
* 开启视频
*
* @return 描述(只为举例需要)
*/
- (NSString *)play;
/**
* 暂停视频
*
* @return 描述(只为举例需要)
*/
- (NSString *)pause;
/**
* 停止播放
*
* @return 描述(只为举例需要)
*/
- (NSString *)stop;
@end
#import "LHPlayer.h"
#import "LHPlayerProtocol.h"
#import "LHAVPlayer.h"
#import "LHIJKPlayer.h"
@interface LHPlayer ()
{
id<LHPlayerProtocol> player;
}
@end
@implementation LHPlayer
- (instancetype)initWithType:(EPlayerType)type
{
self = [super init];
if (self) {
[self initPlayerWithType:type];
}
return self;
}
// 初始化播放器
- (void)initPlayerWithType:(EPlayerType)type{
switch (type) {
case EPlayerType_AVPlayer:
{
player = [[LHAVPlayer alloc] init];
break;
}
case EPlayerType_IJKPlayer:
{
player = [[LHIJKPlayer alloc] init];
break;
}
}
}
//开启视频
- (NSString *)play{
return [player lh_play];
}
//暂停视频
- (NSString *)pause{
return [player lh_pause];
}
//停止播放
- (NSString *)stop{
return [player lh_stop];
}
@end
View Code
下面看客户端的调用。
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
#import "ViewController.h"
#import "LHPlayer.h"
@interface ViewController ()
{
LHPlayer *player;
}
@property (weak, nonatomic) IBOutlet UIButton *btnAVPlayer;
@property (weak, nonatomic) IBOutlet UIButton *btnIjkplayer;
@property (weak, nonatomic) IBOutlet UILabel *lbState;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initPlayerWithType:EPlayerType_IJKPlayer];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
// 初始化播放器
- (void)initPlayerWithType:(EPlayerType)type{
if (player) {
player = nil;
}
player = [[LHPlayer alloc] initWithType:type];
}
#pragma mark -
#pragma makr Button Event
// 选择AVPlayer
- (IBAction)btnAVPlayerEvent:(UIButton *)sender {
sender.selected = YES;
_btnIjkplayer.selected = NO;
[self initPlayerWithType:EPlayerType_AVPlayer];
}
// 选择Ijkplayer
- (IBAction)btnIjkplayerEvent:(UIButton *)sender {
sender.selected = YES;
_btnAVPlayer.selected = NO;
[self initPlayerWithType:EPlayerType_IJKPlayer];
}
// 播放器播放视频
- (IBAction)btnPlayerEvent:(UIButton *)sender {
_lbState.text = player ? [player play] : @"播放器为空";
}
// 播放器暂停视频
- (IBAction)btnPauseEvent:(UIButton *)sender {
_lbState.text = player ? [player pause] : @"播放器为空";
}
// 播放器停止视频
- (IBAction)btnStopEvent:(UIButton *)sender {
_lbState.text = player ? [player stop] : @"播放器为空";
}
@end
View Code
例2、switch,if-else之类的分支语句,此类语句给人的直观感觉是判断条件明确,代码层次清晰,缺点可能是代码繁琐,杂乱无章,而且拆分困难。特别是到后期维护代码的时候,这种状况往往令人有食之无味,弃之可惜的感觉。使用策略模式可以代替switch或if-else之类的代码。
举个例子,以下是小明的计划安排:
周一打篮球
周二逛街
周三洗衣服
周四打游戏
周五唱歌
其他休息
借助策略模式我们可以这样实现代码:
@interface XiaoMing : NSObject
- (void)doSomethingWithDayStr:(NSString *)dayStr params:(NSDictionary *)paramsDict;
@end
#import "XiaoMing.h"
@interface XiaoMing()
@property(nonatomic,copy)NSDictionary *strategyDict;//策略
@property(nonatomic,copy)NSDictionary *paramDict;//参数
@end
@implementation XiaoMing
- (void)doSomethingWithDayStr:(NSString *)dayStr params:(NSDictionary *)paramsDict{
self.paramDict = paramsDict;
if (self.strategyDict[dayStr]){
NSInvocation *doWhat = self.strategyDict[dayStr];
[doWhat invoke];
}else{
[self sleep];
}
}
- (NSInvocation *)invocationWithMethod:(SEL)selector{
NSMethodSignature*signature = [[self class] instanceMethodSignatureForSelector:selector];
if (signature == nil) {
NSString *reason = [NSString stringWithFormat:@"提示:The method[%@] is not find", NSStringFromSelector(selector)];
@throw [NSException exceptionWithName:@"错误" reason:reason userInfo:nil];
}
NSInvocation*invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.target = self;
invocation.selector = selector;
NSDictionary *param = self.paramDict;
//index表示第几个参数,注意0和1已经被占用了(self和_cmd),所以我们传递参数的时候要从2开始。
[invocation setArgument:&(param) atIndex:2];
return invocation;
}
- (void)playBasketball:(NSDictionary *)dict{
NSLog(@"方法:%s 参数:%@",__FUNCTION__,dict);
}
- (void)shopping:(NSDictionary *)dict{
NSLog(@"方法:%s 参数:%@",__FUNCTION__,dict);
}
- (void)washClothes:(NSDictionary *)dict{
NSLog(@"方法:%s 参数:%@",__FUNCTION__,dict);
}
- (void)playGames:(NSDictionary *)dict{
NSLog(@"方法:%s 参数:%@",__FUNCTION__,dict);
}
- (void)sing:(NSDictionary *)dict{
NSLog(@"方法:%s 参数:%@",__FUNCTION__,dict);
}
- (void)sleep{
NSLog(@"这是其他情况:%s",__FUNCTION__);
}
- (NSDictionary *)strategyDict{
if (_strategyDict == nil) {
_strategyDict = @{
@"day1" : [self invocationWithMethod:@selector(playBasketball:)],
@"day2" : [self invocationWithMethod:@selector(shopping:)],
@"day3" : [self invocationWithMethod:@selector(washClothes:)],
@"day4" : [self invocationWithMethod:@selector(playGames:)],
@"day5" : [self invocationWithMethod:@selector(sing:)]
};
}
return _strategyDict;
}
@end
外部调用可以完全不再使用if-else
的判断了。
XiaoMing *xm = [[XiaoMing alloc]init];
//各种情况直接赋值给dayStr即可。
NSString *dayStr = @"day3";
[xm doSomethingWithDayStr:dayStr params:@{@"key":@"test"}];