上篇文章中介绍了行为型模式中的状态模式,这篇文章我们来讨论同样是行为型模式的一种且与状态模式的类图完全相同但本质大有不同的策略模式。
还是先假设一个业务场景,在深圳乘地铁有多种支付方式,包括乘车码、单程票、深圳通和Apple Pay等等,针对不同的支付方式后台会有不同的处理方式,在这里我们仅仅输出一下支付方式。通用的实现方法如下:
public void payment(String paymentMethod){
switch(paymentMethod){
case "乘车码":
System.out.println("乘客通过微信中的乘车码小程序支付.....");
break;
case "单程票":
System.out.println("乘客通过地铁站购买的单程票支付......");
break;
case "深圳通":
System.out.println("乘客通过深圳通卡支付......");
break;
case "Apple Pay":
System.out.println("乘客通过苹果手机的Apple Pay支付......");
break;
default:
System.out.println("你想逃票???");
}
}
很容易可以看出来耦合度真的很高,无论是支付方式的改变还是后台处理方式的改变都需要去修改这个主方法,即违反了开闭原则。这个时候就需要用到我们要提到的策略模式。
策略模式
定义了算法族,分别封装起来,让它们之间可以互相替换。此模式让算法的变化独立于使用算法的客户。
结合定义我们可以看出上面例子中可以互相替换的就是支付方式,改变的也是支付方式,因此我们只要把支付方式封装起来就能有效降低代码耦合度(设计原则中提到过把变化的部分封装起来)。
类图
具体实现
抽象策略接口:
interface PaymentMethods{
//支付
void payOff();
}
具体算法:
//乘车码支付
class RidingCode implements PaymentMethods{
@Override
public void payOff() {
System.out.println("乘客通过微信中的乘车码小程序支付.....");
}
}
//单程票支付
class OneWayTicket implements PaymentMethods{
@Override
public void payOff() {
System.out.println("乘客通过地铁站购买的单程票支付......");
}
}
//深圳通支付
class ShenZhenTong implements PaymentMethods{
@Override
public void payOff() {
System.out.println("乘客通过深圳通卡支付......");
}
}
//ApplePay支付
class ApplePay implements PaymentMethods{
@Override
public void payOff() {
System.out.println("乘客通过苹果手机的Apple Pay支付......");
}
}
上下文角色,在本例中为闸机:
class Gate {
private PaymentMethods paymentMethod;
Gate(PaymentMethods paymentMethod){
this.paymentMethod = paymentMethod;
}
public void payOff(){
System.out.println("乘客要经过闸机啦......");
paymentMethod.payOff();
}
}
测试程序及输出结果:
测试程序:
public static void main(String[] args) {
ApplePay applePay = new ApplePay();
Gate gate = new Gate(applePay);
gate.payOff();
}
输出结果:
乘客要经过闸机啦......
乘客通过苹果手机的Apple Pay支付......
从上述具体实现代码可以看出如果需要增加或删除某个支付方式除了修改自身代码对其他部分程序不影响,符合开闭原则。但策略模式要求客户端(本例中即测试程序)知道每个算法的区别以便于知晓自己要用哪个算法,在本例中如果乘客用的是安卓系统并且没有深圳通也没有购买单程票,那只能通过乘车码支付,因为其他的算法不适用。与状态模式类似,如果算法族中的算法较多使用策略模式会产生过多的类。