设计模式(十一)—— 策略模式
一、定义:
定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
二、特点:
- 环境类(Context):用一个ConcreteStrategy对象来配置。维护一个对Strategy对象的引用。可定义一个接口来让Strategy访问它的数据。
- 抽象策略类(Strategy):定义所有支持的算法的公共接口。 Context使用这个接口来调用某ConcreteStrategy定义的算法。
- 具体策略类(ConcreteStrategy):以Strategy接口实现某具体算法。
三、情景:
设计一个鸭子,会有很多种不同的鸭子,比如说白头鸭、黑头鸭、橡皮鸭、木头鸭等等,这些鸭,有的会叫,有的不会,有的会飞,有的不会,但每一个鸭都会游泳。让你来设计要怎么设计。
设计一:最差的方法
有多少只鸭就建多少个类,这样重复性的工作量太大,代码会十分的难看
设计二:稍微好一点的方法
对这些鸭抽象一下,比如说所有的鸭都会游泳,就创建一个抽象类,类中实现了游泳的方法。
其他的叫、飞等行为写在每个鸭的实现类中。
设计三:再优化一点的方法
把叫和飞这两种行为再抽象出来,形成两个接口,每个鸭都要继承抽象鸭,并且实现飞和叫这两种接口。
但这样有一个问题,有些鸭其实都可以叫的,而且叫的方式都一毛一样。如果每个都这么写得话,也会带来挺大的工作量,所以还需要再进一步优化
设计四:最终优化
将叫和飞两种行为接口,作为实例放到抽象鸭的类中,使用面向接口的方式来实现
如
抽象鸭类
public abstract class Duck {
FlyBehavior flyBehavior;
JiaoBehavior jiaoBehavior;
.........
}
鸭会飞行为实现类
public class CanFly implements FlyBehavior
{
}
某具体的种类的鸭
public class ZhouHeiDuck extends Duck{
public ZhouHeiDuck(){
flyBehavior = new CanFly();
}
}
总结
上面的例子很具有代表性。也反映了设计的两个原则:
1、需要改变的东西和不需要改变的东西要分离开,确切的说,应该要将会改变的东西独立出来
2、针对于接口编程而不是针对于实现编程
应用场景
使用注解实现对支付方式的策略封装
定义注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface PayType {
String desc();
PayTypeEnum type();
}
定义枚举类
public enum PayTypeEnum {
ALIPAY(1),
WECHAT(2);
PayTypeEnum(int type) {
this.type = type;
}
private int type;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
}
定义接口与实现类
public interface IPayService {
String pay(BigDecimal amount);
}
@Service
@PayType(desc = "微信支付", type = PayTypeEnum.WECHAT)
public class WechatPayService implements IPayService {
@Override
public String pay(BigDecimal amount) {
System.out.println("微信到帐{}元!" + amount);
return "success";
}
}
@Service
@PayType(desc = "支付宝支付",type = PayTypeEnum.ALIPAY)
public class AlipayPayService implements IPayService{
@Override
public String pay(BigDecimal amount) {
System.out.println("支付宝到帐{}元!"+amount);
return "success";
}
}
网关类
@Service
public class PayGateWayService {
@Autowired
private List<IPayService> payServiceList;
public IPayService route(int type) throws Exception {
for (IPayService payService : payServiceList) {
PayType payTypeAnnotation = payService.getClass().getAnnotation(PayType.class);
if (payTypeAnnotation.type().getType() == type) {
System.out.println("路由到具体的支付业务类为:" + payService.getClass().getSimpleName());
return payService;
}
}
throw new Exception("没有找到具体支付业务类");
}
}
测试类
@Test
public void test() {
int type = PayTypeEnum.WECHAT.getType();//支付宝支付
BigDecimal amount = BigDecimal.valueOf(100);//支付金额 100 元
IPayService payService = null;//支付网关类
try {
payService = payGateWayService.route(type);
payService.pay(amount);//开始支付
} catch (Exception e) {
System.out.println("支付异常");
}
}
关于作者
后端程序员,五年开发经验,从事互联网金融方向。技术公众号「清泉白石」。如果您在阅读文章时有什么疑问或者发现文章的错误,欢迎在公众号里给我留言。