Preview
Skip to content
CodingDiary
返回

设计模式之行为型设计模式-策略模式

编辑页面
导读

支付宝、微信、京东、银联……一堆 if-else 判断支付方式?策略模式帮你优雅消灭!本文用「选择支付方式」的场景讲解:定义 Payment 接口,不同支付方式各自实现。JDK 的 Comparator、Spring 的 Resource 都是典型应用。符合开闭原则,扩展新支付只需新增类。

1. 模式简介

定义了一系列算法、分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户。可以避免多重分支的 if...else...switch 语句。属于行为型设计模式

2. 示例代码

/**
 * <p>
 * 支付策略
 * </p>
 *
 * @author yangkai.shen
 * @date Created in 2019/8/28 14:43
 */
public enum PaymentStrategy {
    /**
     * 支付宝
     */
    ALI_PAY,
    /**
     * 微信支付
     */
    WECHAT_PAY,
    /**
     * 京东支付
     */
    JD_PAY,
    /**
     * 银联支付
     */
    UNION_PAY;

    /**
     * 支付方式容器池
     */
    private static Map<PaymentStrategy, Payment> PAYMENT_POOL = new HashMap<>();

    static {
        PAYMENT_POOL.put(ALI_PAY, new AliPayment());
        PAYMENT_POOL.put(WECHAT_PAY, new WeChatPayment());
        PAYMENT_POOL.put(JD_PAY, new JdPayment());
        PAYMENT_POOL.put(UNION_PAY, new UnionPayment());
    }

    /**
     * 选择支付方式
     *
     * @param strategy 支付策略
     * @return 支付方式
     */
    public static Payment choose(PaymentStrategy strategy) {
        Payment payment = PAYMENT_POOL.get(ALI_PAY);

        if (PAYMENT_POOL.containsKey(strategy)) {
            payment = PAYMENT_POOL.get(strategy);
        }

        System.out.println("欢迎使用: " + payment.channelName());
        return payment;
    }
}
/**
 * <p>
 * 支付接口
 * </p>
 *
 * @author yangkai.shen
 * @date Created in 2019/8/28 14:31
 */
public interface Payment {
    /**
     * 支付渠道
     *
     * @return 支付渠道
     */
    String channelName();

    /**
     * 余额
     *
     * @return 账户余额
     */
    double balance();

    /**
     * 支付金额
     *
     * @param money 金额
     */
    void pay(double money);
}

/**
 * <p>
 * 支付宝支付
 * </p>
 *
 * @author yangkai.shen
 * @date Created in 2019/8/28 14:38
 */
public class AliPayment implements Payment {
    /**
     * 支付渠道
     *
     * @return 支付渠道
     */
    @Override
    public String channelName() {
        return "支付宝支付";
    }

    /**
     * 余额
     *
     * @return 账户余额
     */
    @Override
    public double balance() {
        return 800;
    }

    /**
     * 支付金额
     *
     * @param money 金额
     */
    @Override
    public void pay(double money) {
        if (balance() < money) {
            System.err.println("余额不足,当前余额:" + balance());
        } else {
            System.out.println("支付成功,交易金额:" + money);
        }
    }
}

/**
 * <p>
 * 京东支付
 * </p>
 *
 * @author yangkai.shen
 * @date Created in 2019/8/28 14:38
 */
public class JdPayment implements Payment {
    /**
     * 支付渠道
     *
     * @return 支付渠道
     */
    @Override
    public String channelName() {
        return "京东支付";
    }

    /**
     * 余额
     *
     * @return 账户余额
     */
    @Override
    public double balance() {
        return 500;
    }

    /**
     * 支付金额
     *
     * @param money 金额
     */
    @Override
    public void pay(double money) {
        if (balance() < money) {
            System.err.println("余额不足,当前余额:" + balance());
        } else {
            System.out.println("支付成功,交易金额:" + money);
        }
    }
}

/**
 * <p>
 * 微信支付
 * </p>
 *
 * @author yangkai.shen
 * @date Created in 2019/8/28 14:38
 */
public class WeChatPayment implements Payment {
    /**
     * 支付渠道
     *
     * @return 支付渠道
     */
    @Override
    public String channelName() {
        return "微信支付";
    }

    /**
     * 余额
     *
     * @return 账户余额
     */
    @Override
    public double balance() {
        return 1234;
    }

    /**
     * 支付金额
     *
     * @param money 金额
     */
    @Override
    public void pay(double money) {
        if (balance() < money) {
            System.err.println("余额不足,当前余额:" + balance());
        } else {
            System.out.println("支付成功,交易金额:" + money);
        }
    }
}

/**
 * <p>
 * 银联支付
 * </p>
 *
 * @author yangkai.shen
 * @date Created in 2019/8/28 14:38
 */
public class UnionPayment implements Payment {
    /**
     * 支付渠道
     *
     * @return 支付渠道
     */
    @Override
    public String channelName() {
        return "银联支付";
    }

    /**
     * 余额
     *
     * @return 账户余额
     */
    @Override
    public double balance() {
        return 10;
    }

    /**
     * 支付金额
     *
     * @param money 金额
     */
    @Override
    public void pay(double money) {
        if (balance() < money) {
            System.err.println("余额不足,当前余额:" + balance());
        } else {
            System.out.println("支付成功,交易金额:" + money);
        }
    }
}
/**
 * <p>
 * 策略模式,测试类
 * </p>
 *
 * @author yangkai.shen
 * @date Created in 2019/8/28 14:54
 */
public class PatternTest {
    public static void main(String[] args) {
        Payment payment = PaymentStrategy.choose(PaymentStrategy.ALI_PAY);
        payment.pay(200);

        System.out.println("--------------------");

        payment = PaymentStrategy.choose(PaymentStrategy.UNION_PAY);
        payment.pay(200);
    }
}
欢迎使用: 支付宝支付
支付成功,交易金额:200.0
--------------------
欢迎使用: 银联支付
余额不足,当前余额:10.0

3. UML 图例

设计模式-行为型设计模式-策略模式

4. 应用

// JDK 的 Comparator 接口,比如:
// java.util.Arrays#parallelSort(int[], int, int)
// java.util.TreeMap#TreeMap(java.util.Comparator<? super K>)

// Spring 的 Resource 接口,比如:
// ClassPathResource
// UrlResource
// FileUrlResource
// FileSystemResource
// ClassPathResource
// ByteArrayResource
// InputStreamResource

5. 场景

6. 优缺点

优点: 1、策略模式符合开闭原则。2、避免使用多重条件转移语句,如if…else…语句、switch语句。3、使用策略模式可以提高算法的保密性和安全性。

缺点: 1、客户端必须知道所有的策略,并且自行决定使用哪一个策略类。 2、代码中会产生非常多策略类,增加维护难度。

7. 完整代码地址

https://github.com/xkcoding/design-pattern/tree/master/src/main/java/com/xkcoding/design/pattern/behavioral/strategy


编辑页面
分享到:

上一篇
设计模式之结构型设计模式-适配器模式
下一篇
GitHub Actions 初体验