策略模式vs工厂模式的区别

帅比萌擦擦* 提交于 2020-01-12 16:00:26

定义:

工厂模式的思想主要为:多个类似的子类继承同一个父类,对其父类中的变量进行操作;工厂类负责判断、控制哪个子类被执行,而工厂类调用子类完成后,返回的结果是该子类的父类,该父类中的变量已经被操作过了,访问该父类,得到我们想要的结果
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

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"}];

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!