策略模式

一、简述

在之前的工厂模式中,为了创建不同的产品使用了switch case(或if else)的形式实现代码,这样违背了开闭原则,即对扩展开放、对修改封闭,维护的成本会随着cese(或else)的增加而增加,而本文的策略模式能较好地解决这个问题。

定义:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。策略模式让算法独立于它的使用者之外,可以自由修改。

来看看UML图,图中主要由三个部分组成

  • Context:上下文环境,持有Strategy引用
  • Strategy:抽象策略,接口(或抽象类)
  • ConcreteStrategy:具体实现策略,实现了具体的算法

Strategy是使用接口还是抽象类,这个取决于一系列的策略中是否有共同属性或方法;如果没有,使用接口更加灵活方便,反之使用抽象类,抽象类中便可存放公共的属性以及方法。

二、简单实现

我们可以来一场说走就走的旅行,背上行囊,出发去丽江。这个时候我们就需要考虑出行方式和价格的问题了(贫穷)。我们可能需要知道飞机、火车、自驾的花费都是多少,再决定什么方式出行。我们先看看最简单的实现方式

2.1 原始代码

public class LetGo {
    public static final String MODE_AIRPLAN = "airPlan";
    public static final String MODE_TRAVEL = "travel";
    public static final String MODE_CAR = "car";

    public void printSpend() {
        Log.i(TAG, "出行花费: ¥" + getSpend(MODE_AIRPLAN));
    }

    private int needSpend(String mode) {
        switch (mode) {
            case MODE_AIRPLAN:
                return 1400;
            case MODE_TRAVEL:
                return 500;
            case MODE_CAR:
                return 2400;
                //异常值
            default:
                return -1;
        }
    }
}

如同前文所说的,当需要添加可选的出行方案时,我们不得不去修改needSpend()函数中的switch case来达到目的;然而这样并不利于后期的维护。接下来,试着使用策略模式来使实现这个简单的出行案例。

2.2 策略模式代码

既然,出行方案是可选的策略,就可以先抽象出一个出行策略的接口,包含needSpend()方法,返回出行花费的方法

public interface ITravelStrategy {
    public int needSpend();
}

接着,实现各种具体出行方案需要的类,在needSpend()方法返回该出行方案所需的费用。

/** 飞机出行 */
public class AirPlanStrategy implements ITravelStrategy {
    @Override
    public int needSpend() {
        return 1400;
    }
}

/** 火车出行 */
public class TrainStrategy  implements ITravelStrategy {
    @Override
    public int needSpend() {
        return 500;
    }
}

/** 自驾出行 */
public class CarStrategy  implements ITravelStrategy {
    @Override
    public int needSpend() {
        return 2400;
    }
}

这里,我们需要的策略就已经完成了,就等着我们选一种方案,看看所需要的花费。我们创建一个类,和Strategy组合使用来获取各种出行方的花费,并在printSpend()方法中打印出行所需的花费。

public class LetGo {
    ITravelStrategy mTravelStrategy;
    
    public LetGo(@NonNull ITravelStrategy strategy){
        mTravelStrategy = strategy;
    }
    
    public void printSpend(){
        Log.i(TAG, "出行花费: ¥" + mTravelStrategy.needSpend());
    }
}

以上的代码就可以完成自驾游花费的输出,策略模式我们就完成了。现在代码是不是比之前使用switch case实现的代码结构更加清晰、简洁。如果需要知道更多的出行方式的花费,只需要实现再实现ITravelStrategy接口,替换掉传入LetGo构造器的参数即可。

//输出自驾游花费
LetGo letGo = new LetGo(new CarStrategy()):
letGo.printSpend();

三、总结

策略模式,其实可以简单地理解成,将过多的switch casecase的代码封装成一个个具有共性的对象,需要什么我们就直接使用什么;对于这种共性的实现就利用interface或者是抽象类来实现。这从对代码的封装以及解耦的角度来理解,可能会更加容易理解。

使用场景

  • 针对同一类问题的多种处理方式,仅仅是具体行为有差别时
  • 需要安全的封装多种同一类型的操作时
  • 出现同一抽象类的多个子类,而有需要使用switch caseif else来选择具体子类时

优点

  • 结构清晰、简单直观
  • 耦合度低,方便扩张
  • 操作封装更加彻底,数据更安全

缺点

  • 使用者必须熟知具策略的使用方式
  • 随着策略的增加,具体的策略子类也会变得更多

作者:MrTrying
链接:https://www.jianshu.com/p/045df9bbcac6
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值