设计模式-策略模式

定义: 定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法独立于使用它的客户而变化,也称为政策模式(policy)。策略模式是一种对象行为型模式。

动机:有许多算法可以实现某一功能, 如排序算法实现方式有冒泡、选择、堆排序、快速排序、希尔排序等,要想实现一个排序用不同的方式, 一种常用的方法就是Hard Coding, 一个类中写若干个方法, 每一个方法对应着一种算法,再或者写一个方法,通过变量和万能的if else大发进行选择。这两种方式同属于Hard Coding(原因是当我们增加一种新的排序算法,需要修改封装算法类的源代码,更换查找算法,也需要修改客户端调用代码), 随着将来的聪明人发明的排序算法越来越多,必将导致算法类越来越复杂, 越来越难以维护。

看来这个算法类是要不得的,那干脆将算法直接放在“客户端”中,这种做法显然更不可取。

那么动机这时候就来了,我们可以定义一些独立的类来封装不同的算法,每一个类封装一个具体的算法,每一个封装算法得类我们都可以称之为策略,为了保证策略的一致性, 一般会用一个抽象的策略类来做算法的定义,而具体的实现交由具体的算法类处理。

使用策略模式时,我们可以定义一些策略类,每一个策略类中封装一种具体的算法。在这里,每一个封装算法的类我们都可以称之为一种策略,根据传入不同的策略类,使环境类执行不同策略类中的算法。

类图:

角色分析:

  • Context 环境类
  • Strategy 抽象策略类或者协议
  • ConcreteStrategy 具体策略 类

实例: 我们我们有两个智能语音服务,平时的状态没有那么多的并发,选用普通的服务就行,但是,活动期间,并发陡增,则需要切换到高级的服务才能满足条件,就是根据不同的场景选用不同的策略.

1
2
3
4
5
@interface SmartVoiceProtocal : NSObject

- (void)fv_startService;

@end

具体的策略类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

@interface NormalSVPlan : NSObject<SmartVoiceProtocal>

- (void)fv_startService;

@end

@implementation NormalSVPlan

- (void)fv_startService
{
NSLog(@"正常状态服务");
}

@end

@interface HighSVPlan : NSObject<SmartVoiceProtocal>

- (void)fv_startService;

@end

@implementation HighSVPlan

- (void)fv_startService
{
NSLog(@"高并发正常状态服务");
}

@end

环境类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@interface SVService: NSObject

@proeprty (nonatomic, strong) id<SmartVoiceProtocal>plan;

- (void)startService;

@end

@implementation SVService

- (void)startService
{
[self.plan fv_startService];
}

@end

使用

1
2
3
4
5
6
7
8
// 上下文类
SVService *service = [SVService alloc] init];
service.plan = [NormalSVService alloc] init]:
[service startService];
// 改变策略
service.plan = [HighSVService alloc] init];
[service startService];

优点:

  • 策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
  • 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族,恰当使用继承可以把公共的代码移到抽象策略类中,从而避免重复的代码。
  • 策略模式提供了一种算法的复用机制,由于将算法单独提取出来封装在策略类中,因此不同的环境类可以方便地复用这些策略类。
  • 使用策略模式可以避免使用多重条件转移语句。

缺点:

  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
  • 策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。