概述
在现实生活中常常遇到实现某种目标存在多种策略可供选择的情况,例如,出行旅游可以乘坐飞机、乘坐火车、骑自行车或自己开私家车等,超市促销可以釆用打折、送商品、送积分等方法。
在软件开发中也常常遇到类似的情况,当实现某一个功能存在多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能,如数据排序策略有冒泡排序、选择排序、插入排序、二叉树排序等。
如果使用多重条件转移语句实现(即硬编码),不但使条件语句变得很复杂,而且增加、删除或更换算法要修改原代码,不易维护,违背开闭原则。如果采用策略模式就能很好解决该问题。
(转:http://c.biancheng.net/view/1378.html)
定义
定义一系列的算法,把每一个算法封装起来,并且使他们可互相替换。策略模式使得算法可独立于使用它的客户而独立变化
举个栗子
还是以武侠小说为例。张无忌作为一个大侠会遇到很多对手,如果每遇到一个对手他都用自己最厉害的武功去迎战,显然是不明智的,于是张无忌想出了3种应战的策略,分别对付3个实力层次的对手。
定义策略接口
策略接口有一个fighting方法用于战斗
public interface FightingStrategy {
public void finghting();
}
具体策略实现
分别定义3个策略来实现接口,用来对付3个实力层次的对手,代码如下
public class WeakRivalStrategy implements FightingStrategy {
@Override
public void finghting() {
System.out.println("遇到了较弱的对手,张无忌使用太极剑");
}
}
public class CommonRivalStrategy implements FightingStrategy {
@Override
public void finghting() {
System.out.println("遇到了普通的对手,张无忌使用圣火令神功");
}
}
public class StrongRivalStrategy implements FightingStrategy {
@Override
public void finghting() {
System.out.println("遇到了强大的对手,张无忌使用乾坤大挪移");
}
}
上下文角色
上下文角色的构造方法包含了策略类,通过传进来不同的具体策略来调用不同策略的finghting方法,如下所示
public class Context {
private FightingStrategy fightingStrategy;
public Context(FightingStrategy fightingStrategy){
this.fightingStrategy = fightingStrategy;
}
public void fighting(){
fightingStrategy.finghting();
}
}
客户端调用
张无忌对不同实力层次的对手,采用了不同的策略来应战。
public class Client {
public static void main(String[] args) {
Goods goods1 = GoodsFactory.getGoods("iPhone7");
goods1.showGoodsPrice("32G");
Goods goods2 = GoodsFactory.getGoods("iPhone7");
goods1.showGoodsPrice("32G");
Goods goods3 = GoodsFactory.getGoods("iPhone7");
goods1.showGoodsPrice("128G");
}
}
策略模式的使用场景和优缺点
- 使用场景
- 对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
- 针对同一类型问题的多种处理方式,仅仅是具体行为有差别时
- 在一个类中定义了很多行为,而且这些行为在这个类里的操作以多个条件语句的形式出现。策略模式将相关的条件分支移入它们各自的Strategy类中,以代替这些条件语句
- 优点
- 使用策略模式可以避免使用多重条件语句。多重条件语句不易维护,而且容易出错。
- 易于扩展。当需要添加一个策略时,只需要实现接口就可以了。
- 缺点
- 每一个策略都是一个类,复用性小。如果策略过多,类的数量会增多。
- 上层模块必须知道有哪些策略,才能够使用这些策略,这与迪米特原则相违背
借鉴:刘望舒《Android进阶之光》