正文
策略模式介绍
基础理论
策略模式作为二十三种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
我们查阅
NSArrayAPI文档时会发现,有下面这一段话Remember that
NSArrayis 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~