正文
策略模式介绍
基础理论
策略模式作为二十三种GoF软件设计模式的其中一种,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。
—— 维基百科
深入理解
- 所谓策略模式,本质就是将需要使用的算法抽象成一个持有的算法对象。在构造函数中选择具体的算法初始化持有的算法对象;在原本使用算法的地方,使用该算法对象调用算法。
- 根据上述定义,我认为策略模式有以下形式:
- 形式:策略上下文类 + 抽象父类 / 接口 + 具体子类
- 如果单独使用策略模式,我们会需要在客户类创建具体的策略类对象,这时我们可以将策略模式与简单工厂模式结合使用,减少客户端的判断代码,两者配套食用,味道更佳!
UML图
优与劣
- 优:以相同的形式调用所有的算法,降低算法类与使用算法的类(策略上下文类)的耦合度
- 劣:扩展时违反开闭原则(OCP,Open Closed Principle),当新增加子类的时候,需要修改策略上下文类
策略模式的使用实例
下面以一个简单的磁盘调度算法为例(算法实现仅用输出代替),讲述策略模式的应用
创建父类:在本例中,父类为磁盘调度算法类
1234567891011121314151617// DiskSchedulingAlgorithm.h@interface DiskSchedulingAlgorithm : NSObject- (void)run;@end// DiskSchedulingAlgorithm.m@implementation DiskSchedulingAlgorithm- (void)run {NSAssert(NO, @"virtual implement shouldn`t be called by");}@end创建继承于父类的子类:本例中,子类为具体的磁盘调度算法类,负责实现具体算法。此处子类重写父类方法,以便合理使用多态
12345678910111213141516171819// CSCANAlgorithm.h@interface CSCANAlgorithm : DiskSchedulingAlgorithm- (void)run;@end// CSCANAlgorithm.m@implementation CSCANAlgorithm- (void)run {NSLog(@"Do the CSCAN Algorithm");}@end12345678910111213141516171819// SCANAlgorithm.h@interface SCANAlgorithm : DiskSchedulingAlgorithm- (void)run;@end// SCANAlgorithm.m@implementation SCANAlgorithm- (void)run {NSLog(@"Do the SCAN Algorithm");}@end12345678910111213141516171819// SSTFAlgorithm.h@interface SSTFAlgorithm : DiskSchedulingAlgorithm- (void)run;@end// SSTFAlgorithm.m@implementation SSTFAlgorithm- (void)run {NSLog(@"Do the SSTF Algorithm");}@end12345678910111213141516171819// FCFSAlgorithm.h@interface FCFSAlgorithm : DiskSchedulingAlgorithm- (void)run;@end// FCFSAlgorithm.m@implementation FCFSAlgorithm- (void)run {NSLog(@"Do the FCFS Algorithm");}@end实现策略上下文类:实现父类中的简单工厂方法,根据类型判断返回的实例
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273// Context.h@class DiskSchedulingAlgorithm;@class FCFSAlgorithm;typedef NS_ENUM(NSUInteger, DiskSchedulingAlgorithmType) {kDiskSchedulingCSCANAlgorithmType,kDiskSchedulingSCANAlgorithmType,kDiskSchedulingFCFSAlgorithmType,kDiskSchedulingSSTFAlgorithmType,kDiskSchedulingDefaultAlgorithmType};typedef FCFSAlgorithm DefaultAlgorithmType;@interface Context : NSObject- (void)schedulingDisk;- (instancetype _Nullable)init;- (instancetype _Nullable)initWithDiskSchedulingAlgorithm:(DiskSchedulingAlgorithmType)type;@property (nonatomic, copy, readwrite, nonnull) DiskSchedulingAlgorithm *algorithm;@end// Context.m@implementation Context- (instancetype)init {return [self initWithDiskSchedulingAlgorithm:kDiskSchedulingDefaultAlgorithmType];}// 简单工厂模式实现- (instancetype)initWithDiskSchedulingAlgorithm:(DiskSchedulingAlgorithmType)type {if (self = [super init]) {switch (type) {case kDiskSchedulingCSCANAlgorithmType:_algorithm = [[CSCANAlgorithm alloc] init];break;case kDiskSchedulingSCANAlgorithmType:_algorithm = [[SCANAlgorithm alloc] init];break;case kDiskSchedulingFCFSAlgorithmType:_algorithm = [[FCFSAlgorithm alloc] init];break;case kDiskSchedulingSSTFAlgorithmType:_algorithm = [[SSTFAlgorithm alloc] init];break;case kDiskSchedulingDefaultAlgorithmType:_algorithm = [[DefaultAlgorithmType alloc] init];break;}return self;}return nil;}- (void)schedulingDisk {[_algorithm run];}@end至此,策略模式实现完毕
策略模式在系统框架中的应用
- 以下内容存有不确定性,倘若有误,劳烦告知
NSArray
我们查阅
NSArray
API文档时会发现,有下面这一段话Remember that
NSArray
is the public interface for a class cluster and what this entails for your subclass. You must provide the storage for your subclass and implement the primitive methods that directly act on that storage.与
NSString
类一样,NSArray
亦是一个类簇类。对于类簇类而言,如果我们想要继承它,我们需要处理一系列较为复杂的问题。当我们需要使用NSArray
的行为时(比如在NSArray
之上实现一个栈结构),我们更好地方法是持有NSArray
,而非继承。我们可以将NSArray
当作我们其中一个策略,然后使用该策略去处理问题。
- 总结:本文简述了策略模式的理论以及实践。我认为,策略模式本质是持有对象,并使用该对象去解决问题。我们应该去把握好这个本质。
- 本文代码下载
- 示例代码
- 运行环境:Xcode 8.2.1 (8C1002)
- Last Edited:2017.2.18
- Author:@Seahub
- Please contact me if you want to share this Article, 3Q~