JAVA设计模式之策略模式

本文深入解析策略模式的概念,通过支付方式的选择作为案例,展示了如何将不同算法封装为独立的策略类,实现算法的自由切换和系统扩展。同时,讨论了策略模式的优缺点,以及在实际开发中的应用和注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、什么是策略模式

1、定义:
策略模式(StrategyPattern):定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。是一种对象行为型模式。

打个比方说,我们出门的时候会选择不同的出行方式,比如骑自行车、坐公交、坐火车、坐飞机、坐火箭等等,这些出行方式,每一种都是一个策略。

再打个比方,我们购物下单需要支付时,你可以选择支付宝支付,微信支付,银联支付,每一种支付方式也是一种策略

2、模式结构

环境角色(Context):持有一个策略类的引用,提供给客户端使用。

抽象策略角色(Strategy):这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。

具体策略角色(ConcreteStrategy):包装了相关的算法或行为

UML结构图如下:
在这里插入图片描述

二、具体案例

比如我们就选择支付方式进行案例分析:下订单成功后,需要选择支付方式
在这里插入图片描述
1、抽象策略角色(Strategy):

public interface Payment {
    String pay(String uid, double amount);
}

2、具体策略角色(ConcreteStrategy):

/**
 * 支付宝pay
 */
public class AliPay implements Payment {

    public String pay(String uid,double amount) {
        System.out.println("欢迎使用支付宝");
        System.out.println("查询账户余额,开始扣款");
        return "支付成功,扣款:"+ amount;
    }
}

/**
 * 微信支付
 */
public class WeChatPay implements Payment {

    public String pay(String uid,double amount) {
        System.out.println("欢迎使用银联卡");
        System.out.println("查询账户余额,开始扣款");
        return "支付成功,扣款:"+ amount;
    }
}

/**
 * 银联支付
 */
public class UnionPay implements Payment {

    public String pay(String uid,double amount) {
        System.out.println("欢迎使用银联卡");
        System.out.println("查询账户余额,开始扣款");
        return "支付成功,扣款:"+ amount;
    }
}

3、环境角色(Context):

public class PayContext {
    private Payment payment;

    public PayContext(Payment payment){
        this.payment = payment;
    }

    public String pay(String uid, double amount){
        return payment.pay(uid,amount);
    }
}

4、测试类

/**
 * 订单类
 */
@Data
public class Order {
    private String uid;
    private String orderId;
    private double amount;

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

测试:

public class PayStrategyTest {
    public static void main(String[] args) throws Exception{
        //下单
        Order order = new Order("1","20200311",100);
        PayContext payContext = null;
        //开始支付,选择支付方式:支付宝 ALI_PAY、银联卡 UNION_PAY、微信支付 WECHAT_PAY
        //每个渠道它的支付的具体算法不一样
        String payType = "WECHAT_PAY";
        if("ALI_PAY".equals(payType)){
            payContext = new PayContext(new AliPay());
        } else if("WECHAT_PAY".equals(payType)){
            payContext = new PayContext(new WeChatPay());
        } else if("UNION_PAY".equals(payType)){
            payContext = new PayContext(new UnionPay());
        } else {
            throw new Exception("支付异常");
        }
        System.out.println(payContext.pay(order.getUid(),order.getAmount()));
    }
}

运行结果:

欢迎使用微信支付
查询账户余额,开始扣款
支付成功,扣款:100.0

三、问题和优化

策略模式的功能是把具体的算法实现,从具体的业务处理里面独立出来,把它们实现成为单独的算法类,从而形成一系列的算法,并让这些算法可以相互替换。

策略模式的重心不是如何来实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活、具有更好的维护性和扩展性。

今天下午和公司的架构师聊了一会,聊到了策略模式,才发现其实并不是文章中一开始写到的那样,避免if-else,而是为了遵循程序的开闭原则。

程序中是不可或缺if-else的,我们根据if-else来确定具体应该选择使用哪种策略,当有新的策略行为时,我们就可以新添加一个策略实现,这样就可以避免改动原有的策略代码,从而实现程序的扩展性,已避免改动原有的策略。

所谓开闭原则,也就是说:对扩展是开放的,对修改是关闭的。运行程序的扩展,但是不允许修改原有的程序策略行为。

如果要避免if-else;则需要稍作修改,利用枚举;

修改后:

/**
 * 枚举当作一个常量去维护
 */
public enum PayType {
    ALI_PAY(1,new AliPay()),
    WECHAT_PAY(2,new WeChatPay()),
    UNION_PAY(3,new UnionPay());

    private int code;
    private Payment payment;


    PayType(int code,Payment payment){
        this.code = code;
        this.payment = payment;
    }

    public Payment getValue(){
        return this.payment;
    }
    public int getCode(){
        return this.code;
    }

    public static Payment getPayment(int code) {
        for (PayType payType : PayType.values()) {
            if (code == payType.getCode()) {
                return payType.getValue();
            }
        }
        return null;
    }
}

测试类:

public class PayTest {
    public static void main(String[] args) throws Exception{
        //下单
        Order order = new Order("1","20200311",100);
        //开始支付,选择支付方式:支付宝 ALI_PAY、银联卡 UNION_PAY、微信支付 WECHAT_PAY
        //每个渠道它的支付的具体算法不一样
        int payType = 1;
        PayContext payContext = new PayContext(PayType.getPayment(payType));
        System.out.println(payContext.pay(order.getUid(),order.getAmount()));
    }
}

如上,这样就用枚举取代了if else逻辑,如果需要扩展新的支付方式,只需要新写一个继承支付抽象接口的支付类,然后在美剧中添加相应的信息即可。

四、策略模式的应用

  1. 何时使用
    一个系统有许多类,而区分它们的只是他们直接的行为时

  2. 方法
    将这些算法封装成一个一个的类,任意的替换

  3. 优点
    1)算法可以自由切换
    2)使用策略模式可以避免使用多重条件转移语句。
    3)策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。

  4. 缺点
    1)策略类数量会增多,每个策略都是一个类,复用的可能性很小
    2)客户端必须知道所有的策略类,并自行决定使用哪一个策略类。

  5. 使用场景
    1)多个类只有算法或行为上稍有不同的场景
    2)算法需要自由切换的场景
    3)需要屏蔽算法规则的场景

  6. 应用实例
    1)出行方式,自行车、汽车等,每一种出行方式都是一个策略

  1. 商场促销方式,打折、满减等
    3)Java AWT中的LayoutManager,即布局管理器
  1. 注意事项
    如果一个系统的策略多于四个,就需要考虑使用混合模式来解决策略类膨胀的问题。

  2. 特点
    1)最终执行结果是固定的;
    2)执行过程和执行逻辑不一样;
    查看的很多资料,策略模式无法像网上说的那样完全避免if-else。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值