设计模式篇(八)——策略模式

一、简介

策略模式(Strategy Pattern)状态模式UML 图几乎一模一样,在前面的文章也有过简单的介绍,事实上 策略模式 可以看作是阉割版的 状态模式,在实际的开发过程中,我们会更多的使用到 策略模式

定义:类的行为会根据不同的策略发生改变。

使用场景:例如图片加载框架 Glide,会提供几种缓存策略,使得我们可以自由选择不同的缓存方式。

实现要素:

  1. 将具体的行为抽成一个接口,然后通过该接口制造多个不同实现。
  2. 一定要区分 状态模式策略模式 !!!

对于一个行为突然需要多出一种实现,在代码中这是一个很头疼的事情。例如我要吃饭,每天都是在公司解决,但是周末我在家不能在公司吃饭了,那就只能是点外卖,这时候产品突然到我家夺门而入,对我说超市的猪肉降价了,让我自己做饭吃。如果使用策略模式,早早的定义一个吃饭的行为接口,我们只需要新建个类并且实现该接口,而我只需要持有这个吃饭的策略,不必亲自实现各个吃饭的方法,岂不美哉。

二、实现

以马老师打游戏的为例,大家都知道,马老师需要开启王者模式才能起飞,而开启各个模式就是实行不同的操作策略。

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

四、小结

策略模式 是一个比较容易理解,且具有比较大的实用性,因为其扩展性十分的强,在应对产品变化莫测的需求时,我们也能够从容不迫。到时候产品就是这样的姿态:
卑微产品

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值