一、简介
策略模式(Strategy Pattern) 和 状态模式 的 UML 图几乎一模一样,在前面的文章也有过简单的介绍,事实上 策略模式 可以看作是阉割版的 状态模式,在实际的开发过程中,我们会更多的使用到 策略模式。
定义:类的行为会根据不同的策略发生改变。
使用场景:例如图片加载框架 Glide,会提供几种缓存策略,使得我们可以自由选择不同的缓存方式。
实现要素:
- 将具体的行为抽成一个接口,然后通过该接口制造多个不同实现。
- 一定要区分 状态模式 和 策略模式 !!!
对于一个行为突然需要多出一种实现,在代码中这是一个很头疼的事情。例如我要吃饭,每天都是在公司解决,但是周末我在家不能在公司吃饭了,那就只能是点外卖,这时候产品突然到我家夺门而入,对我说超市的猪肉降价了,让我自己做饭吃。如果使用策略模式,早早的定义一个吃饭的行为接口,我们只需要新建个类并且实现该接口,而我只需要持有这个吃饭的策略,不必亲自实现各个吃饭的方法,岂不美哉。
二、实现
以马老师打游戏的为例,大家都知道,马老师需要开启王者模式才能起飞,而开启各个模式就是实行不同的操作策略。
1、定义接口
操作策略:
interface OperationStrategy{
// 能否起飞
fun canFly():Boolean
// 食欲,返回 x 碗米饭
fun appetite():Int
}
2、实现多个策略
//正常模式
class NormalStrategy : OperationStrategy{
override fun canFly(): Boolean = false
override fun appetite(): Int = 1
}
//菜鸡模式
class VegetableStrategy : OperationStrategy{
override fun canFly(): Boolean = false
override fun appetite(): Int = 10
}
//王者模式
class KingStrategy : OperationStrategy{
override fun canFly(): Boolean = true
override fun appetite(): Int = -1 //因为吐了
}
3、实现马老师
object TeacherMa{
// 操作策略
private lateinit var strategy:OperationStrategy
// 观众数量
var viewers = mutableListOf<Any>()
init {
strategy = NormalStrategy() //默认正常操作
}
/**
* <改变策略>
*/
fun changeStrategy(strategy:OperationStrategy){
this.strategy = strategy
}
/**
* <开始游戏>
*/
fun startGame(){
print("游戏进行中,马老师起飞了吗:${strategy.canFly()}")
if (strategy.appetite()>0){
println(",观众吃了${strategy.appetite()}碗饭。")
}else{
println(",观众吐了。")
}
}
/**
* <检查观众数量,并且改变操作策略>
*/
fun checkViewer(){
if (viewers.size<10){
println("观众变少了,需要开启菜鸡模式!")
changeStrategy(VegetableStrategy())
}else if (viewers.size<100){
println("开启正常模式即可。")
changeStrategy(NormalStrategy())
}else{
println("这么多观众,赶紧开启王者模式装x!")
changeStrategy(KingStrategy())
}
}
}
然后我们再在 Main 方法中简单的操作一番:
fun main() {
TeacherMa.checkViewer()
TeacherMa.startGame()
// 增加 101 个观众
val viewers = mutableListOf<Any>()
repeat(101){
viewers.add(Any())
}
TeacherMa.viewers.addAll(viewers)
TeacherMa.checkViewer()
TeacherMa.startGame()
}
控制台输出:
观众变少了,需要开启菜鸡模式!
游戏进行中,马老师起飞了吗:false,观众吃了10碗饭。
这么多观众,赶紧开启王者模式装x!
游戏进行中,马老师起飞了吗:true,观众吐了。
4、说明
上面的例子中,所有的策略都是由 马老师 自己改变的,这有点 状态模式 的意思,但是一定要搞清楚了:状态模式 中状态会相互转换,而 策略模式 中的策略是不能相互转换,只能是由外界替换策略。
根据不同的场景,你也可以做马老师的金主爸爸,如果你最近没什么胃口,你也可以逼他开启菜鸡模式下饭。
三、相关源码
在 Glide 中,我们可以通过代码:.diskCacheStrategy(DiskCacheStrategy.ALL)
来设置不同的缓存策略。
我们直接查看 DiskCacheStrategy 类:
public abstract class DiskCacheStrategy {
... ...
public abstract boolean isDataCacheable(DataSource dataSource);
public abstract boolean isResourceCacheable(boolean isFromAlternateCacheKey,
DataSource dataSource, EncodeStrategy encodeStrategy);
public abstract boolean decodeCachedResource();
public abstract boolean decodeCachedData();
}
这个类就是缓存策略的抽象,其中的4个方法就是每个不同策略下需要的进行的差异化设置。
再看看其具体实现,我们发现其实具体的实现类都是匿名类,且都是有一个静态实例:
public abstract class DiskCacheStrategy {
public static final DiskCacheStrategy ALL = new DiskCacheStrategy(){... ...} //先不看具体实现
public static final DiskCacheStrategy NONE = new DiskCacheStrategy(){... ...}
public static final DiskCacheStrategy DATA= new DiskCacheStrategy(){... ...}
public static final DiskCacheStrategy RESOURCE = new DiskCacheStrategy(){... ...}
public static final DiskCacheStrategy AUTOMATIC= new DiskCacheStrategy(){... ...}
... ...
}
以 DiskCacheStrategy.NONE
为例,我们来看看它的实现:
public static final DiskCacheStrategy NONE = new DiskCacheStrategy() {
@Override
public boolean isDataCacheable(DataSource dataSource) {
return false;
}
@Override
public boolean isResourceCacheable(boolean isFromAlternateCacheKey, DataSource dataSource,
EncodeStrategy encodeStrategy) {
return false;
}
@Override
public boolean decodeCachedResource() {
return false;
}
@Override
public boolean decodeCachedData() {
return false;
}
};
所有的方法都是返回 false
,那就说明不需要任何的返回。再看看 DiskCacheStrategy.ALL
:
public static final DiskCacheStrategy ALL = new DiskCacheStrategy() {
@Override
public boolean isDataCacheable(DataSource dataSource) {
return dataSource == DataSource.REMOTE;
}
@Override
public boolean isResourceCacheable(boolean isFromAlternateCacheKey, DataSource dataSource,
EncodeStrategy encodeStrategy) {
return dataSource != DataSource.RESOURCE_DISK_CACHE && dataSource != DataSource.MEMORY_CACHE;
}
@Override
public boolean decodeCachedResource() {
return true;
}
@Override
public boolean decodeCachedData() {
return true;
}
};
四、小结
策略模式 是一个比较容易理解,且具有比较大的实用性,因为其扩展性十分的强,在应对产品变化莫测的需求时,我们也能够从容不迫。到时候产品就是这样的姿态: