策略模式--strategy pattern

属于行为模式--一个类的行为或者其算法可以在运行时更改(策略模式)

策略模式封装了算法或者行为的细节到单独的类中,使算法之间可以相互替换,扩展算法的同时不会影响到其他算法,即是开闭原则的体现。 

使用目的:定义一系列的算法,把他们都封装起来,并且使他们可以相互替换

解决:在有多种算法相似的情况下,使用if,,else所带来的复杂和难以维护

场景:将这些算法封装成一个个类,可以任意替换

关键代码:都是实现同一个接口interface

应用实例

  1. 诸葛亮的锦囊妙计,每一个锦囊就是一个妙计
  2. 旅行的出游方式,选择骑自行车、顺风车、自驾,每一种旅游方式都是一个策略
  3. 支付方式,选择支付宝、微信支付、连连支付等,每一种支付方式都是一种策略
  4. 条条大路同北京,任何一条大路到达北京,则这其中的任何一条大路就是一种策略
  5. 通过url进行爬虫,则任何url都是一种策略
  6. Spring中的动态代理JDK动态代理和CGLIB动态代理,任何一种代理就是一种 策略 

Spring对资源访问的封装是策略模式的经典实现。

  • Spring中的动态代理JDK动态代理和CGLIB动态代理,任何一种代理就是一种 策略
  • spirng 使用Resource接口来抽象资源,接口中定义了一些对资源的操作,
    该接口提供了更强的资源访问能力。Spring 框架本身大量使用了 Resource 接口来访问底层资源。Resource继承了InputStreamSource接口,使其可以获取资源的底层输入流。
    Resource接口有一些不同的实现类,主要有:
    a:UrlResource:访问网络资源的实现类。
    b:ClassPathResource:访问类路径资源。
    c:FileSystemResource:访问文件系统资源。
    d:ServletContextResource:访问相对于
    e:ServletContext路径下的资源的实现类。
    f:InputStreamResource:访问输入流资源的实现类。
    g:ByteArrayResource:访问字节数组资源。

    实现了ResourceLoader接口的类可以获得某个Resource的实例。ApplicationContext也是该接口的子接口,因此ApplicationContext也具有加载资源的能力。

Spring中大量的使用策略模式,这里这里只说这两个例子  

优点:

  •     算法可以自由切换
  • 避免使用多种条件判断
  • 扩展性良好

缺点:

策略类会增多

所有策略都需要对外暴露

什么场景中使用???

  • 如果在一个系统里有许多类,他们之间的区别仅仅在于他们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种
  • 一个系统需要动态地在几种算法中选择一种
  • 如果一个对象有很多行为,如果不使用恰当的模式,这些行为就只好使用多重的条件选择语句实现

注意事项:也不是策略模式就是个万能,如果当系统的策略模式多余四个,就需要考虑使用混合模式,解决策略模式的膨胀问题。

基于上面的这些废话描述,咱们还是用代码来说话,就想你怎么某个人是不是SX,最好的方式就是使用代码来证明他是不是SX。

我们就基于上面提到过的支付方式来写一下代码:

策略模式-java实现_动态代理

AliPay.java代码

策略模式-java实现_面试_02

JDPay.java代码

策略模式-java实现_面试_03

UnionPay.java代码

策略模式-java实现_策略模式_04

Wecaht.java代码

策略模式-java实现_java_05



package com.tian.pattern.strategy;
/**
 * 订单信息
 *
 * @Author tianweichang
 * @Date 2018-08-10 10:54
 **/
public class Order {
/**
     * 订单号
     */
    private String uid;
/**
     * 用户号
     */
    private int userId;
/**
     * 支付金额
     */
    private double amount;
//这个参数,完全可以用Payment这个接口来代替
    //为什么?

    //完美地解决了switch的过程,不需要在代码逻辑中写switch了
    //更不需要写if    else if
    public PayState pay(PayType payType) {
return payType.get().pay(this.uid, this.amount);
    }

public Order() {
    }

public Order(String uid, int userId, double amount) {
this.uid = uid;
this.userId = userId;
this.amount = amount;
    }

public String getUid() {
return uid;
    }

public void setUid(String uid) {
this.uid = uid;
    }

public int getUserId() {
return userId;
    }

public void setUserId(int userId) {
this.userId = userId;
    }

public double getAmount() {
return amount;
    }

public void setAmount(double amount) {
this.amount = amount;
    }
}



策略模式-java实现_策略模式_06



package com.tian.pattern.strategy;

/**
 * 支付完成后的状态
 *
 * @Author tianweichang
 * @Date 2018-08-10 10:56
 **/
public class PayState {
/**
     * 返回码
     */
    private int code;
/**
     * 返回数据
     */
    private Object data;
/**
     * 返回提示
     */
    private String msg;

public PayState(int code, String msg, Object data) {
this.code = code;
this.data = data;
this.msg = msg;
    }

@Override
    public String toString() {
return ("支付状态:[" + code + "]," + msg + ",交易详情:" + data);
    }
}



策略模式-java实现_java_07

策略模式-java实现_面试_08

运行结果:

策略模式-java实现_面试_09

总结:

  • 客户端只要选择某种支付方式就行了,至于是怎么支付的不需要
  • 旅游出行你只要选择你要使用的交通方式就可以了。
  • 去北京你只要选择你走的大路就可以了,
  • .....