1.解析
定义 :
定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
UML :
解释 :
抽象策略角色: 由一个接口或者抽象类实现
具体策略角色: 包装了相关的算法和行为
环境角色: 持有一个策略类的引用
2.实例
场景描述 :
* 支付方式 (环境角色) : 刷卡 ,扫码
*
* 具体刷卡策略: 工商 ,建设 ,农行,广发,邮政
*
* 具体扫码策略:支付宝 ,微信
*
* 描述 :支付中,通过实现不同的支付具体策略,返回 支付机构名称,当前的支付账单码;
*
$1. 策略实现 : 支付方式,即策略家族实现
(1) 支付策略接口实现
public interface PayCompany {
/**
*
* 实现支付公司 返回用户消费的支付公司名称
* 例如 :刷卡,刷的是工商银行的,返回 工商银行;
*/
//返回支付机构名称
String notifiyPayCompanyName();
//返回支付账单号
String notifiyPayCode();
}
(2)策略 1:支付宝支付
public class AlipayStrategy implements PayCompany{
/**
* 支付宝策略
*/
@Override
public String notifiyPayCompanyName() {
return "支付宝";
}
@Override
public String notifiyPayCode() {
Random random=new Random();
return "ALIPAY"+random.nextInt(100000000);
}
}
(3) 策略 2 :农行卡支付
public class NongHangStrategy implements PayCompany {
@Override
public String notifiyPayCompanyName() {
return "农业银行";
}
@Override
public String notifiyPayCode() {
Random random=new Random();
return "NH"+random.nextInt(100000000);
}
}
(4) 策略 3: 工商支付
public class GongShangStrategy implements PayCompany {
@Override
public String notifiyPayCompanyName() {
return "工商银行";
}
@Override
public String notifiyPayCode() {
Random random=new Random();
return "GS"+random.nextInt(100000000);
}
}
$2 .环境角色: 即支付方式 实现 :刷卡消费 ,扫码支付
(1)支付父类实现 : 实现 返回 支付机构 和 账单号 ,策略模式的精华在此实现
public abstract class Pay {
/**
* 所有支付方式的父类 : 刷卡支付 , 扫码支付
*/
public abstract void payMoney(double money);
/**
* 添加拓展功能 : 友好提醒
*/
private PayCompany payCompany;
public void setPayCompany(PayCompany payCompany) {
this.payCompany = payCompany;
}
/**
* 返回支付机构名称
* @return
*/
public String getCompanyName() {
return payCompany.notifiyPayCompanyName();
}
/**
* 返回支付 账单号
* @return
*/
public String getPayCodeNum(){
return payCompany.notifiyPayCode();
}
}
(2)支付方式 1 :刷卡消费
public class CardPay extends Pay {
/**
* 刷卡支付
*/
private String name;
public CardPay(String name,PayCompany paycompany) {
this.name = name;
super.setPayCompany(paycompany);
}
@Override
public void payMoney(double money) {
System.out.println(name + " : 通过刷"+super.getCompanyName()+"卡支付 :" + money + " 元 ( 账单号:"+super.getPayCodeNum()+")");
}
}
(2) 支付方式 2 : 扫码支付
public class CodePay extends Pay {
/**
* 扫码支付
*/
private String name;
public CodePay(String name) {
this.name = name;
super.setPayCompany(new AlipayStrategy());
}
@Override
public void payMoney(double money) {
System.out.println("亲爱的 ,"+name + " :感谢你使用 "+super.getCompanyName()+" 支付 " + money + " 元( 账单号:"+super.getPayCodeNum()+")");
}
}
$3 .测试
public static void main(String[] args) {
//固定的扫码支付
Pay pay=new CodePay("原明卓");
pay.payMoney(1000);
//刷卡支付 :工商银行
Pay gongshang=new CardPay("王五",new GongShangStrategy());
gongshang.payMoney(1220000);
//刷卡支付 :农业银行
Pay nong=new CardPay("C罗 ",new NongHangStrategy());
nong.payMoney(1);
}
结果 :
亲爱的 ,原明卓 :感谢你使用 支付宝 支付 1000.0 元( 账单号:ALIPAY86477278)
王五 : 通过刷工商银行卡支付 :1220000.0 元 ( 账单号:GS92660807)
C罗 : 通过刷农业银行卡支付 :1.0 元 ( 账单号:NH48926324)
3.优缺点
优点:
1、 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码转移到父类里面,从而避免重复的代码。
2、 策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起。决定使用哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能再独立演化。继承使得动态改变算法或行为变得不可能。
3、 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。
缺点:
1、客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
2、 策略模式造成很多的策略类,每个具体策略类都会产生一个新类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用享元模式来减少对象的数量。
4.使用场景
(1)许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。
(2)需要使用一个算法的不同变体。例如,你可能会定义一些反映不同的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时 ,可以使用策略模式。
(3)算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。
(4)一个类定义了多种行为, 并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句。