策略模式(Strategy):它定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法的变化不会影响到使用算法的客户。(原文:The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.)
应用场景: 1、 多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。
2、 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。
3、 对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
关于策略模式,还是来一个小例子吧,大家都知道超市或者网上商城里面经常有各种打折活动,如果我们写一个收费计算系统,关于这块代码怎么设计才好呢?因为打折活动各种情况,各种不同,如何写能够在打折活动修改的时候减少代码的修改,减少出差的概率呢?
想想使用下策略模式:
先看下可以独立出系统的善变的打折接口:
public interface IDiscount { double getPrice(double price, int quantity); }
下面是实现接口的两个打折方法:一、直接打折
public class Rebate implements IDiscount { private double discount; public void setDiscount(double discount){ this.discount = discount; } public double getDiscount(){ return discount; } @Override public double getPrice(double price, int quantity) { // TODO Auto-generated method stub return price*quantity*discount; } }
二、达到一定数额返现金
public class CashReturn implements IDiscount { private int cashCondition; private int cashReturn; public void setCondition(int cashCondition,int cashReturn){ this.cashReturn = cashReturn; this.cashCondition = cashCondition; } @Override public double getPrice(double price, int quantity) { double orignal = price * quantity; int n = (int) (orignal / cashCondition); return orignal - cashReturn * n; } }
收银机:
public class CashRegister { private IDiscount iDiscount; public void setDiscount(IDiscount iDiscount){ this.iDiscount = iDiscount; } public void getAccountReceivable(double price, int quantity){ System.out.println("应收:"+iDiscount.getPrice(price,quantity)); } }
测试:
public static void main(String[] args){ //两种折扣方式 IDiscount rebate = new Rebate(); IDiscount cashReturn = new CashReturn(); CashRegister cashRegister = new CashRegister(); //使用打折 ((Rebate) rebate).setDiscount(0.8); cashRegister.setDiscount(rebate); cashRegister.getAccountReceivable(102.8, 3); //返现金 ((CashReturn) cashReturn).setCondition(200,40); cashRegister.setDiscount(cashReturn); cashRegister.getAccountReceivable(102.8, 3); }
结果:
应收:246.72
应收:268.4
在这里思考下,把善变的部分独立出来,使用委托进行解耦。我的实体部分完成固定功能。使用策略类来实现那些需要调整的功能。
优点:
- 提供了一种替代继承的方法,而且既保持了继承的优点(代码重用)还比继承更灵活(算法独立,可以任意扩展)。
- 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
- 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。
缺点: 1、 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。
在android中使用
listView.setAdapter(),里面的Adapter ,一般都是自定义的Adapter ,继承自BaseAdapter ,这就是典型的策略模式,当ListView 的Item呈现不同形式,在getView方法中,就得不同的实现。