Java设计模式再相识 (十四)——策略模式

目录

  • 策略模式
    • 策略模式的结构
    • 策略模式的实际应用场景
  • 示例
    • 策略模式的优缺点
      • 优点
      • 缺点
  • 总结

策略(Strategy)这个词在不同领域都十分重要,在军事领域,策略关系到行军作战的方法,而在软件开发中,使用合适的策略能让我们的软件更加易于维护。我们常常能遇到某个功能存在多种不同的解决策略的问题。例如排序算法有冒泡排序、选择排序、插入排序、快速排序等方法可供选择。这就可以用到策略模式将算法封装成一个个的策略供使用者调用。策略模式可以整体地替换问题的实现部分,从而更加灵活地解决问题。

策略模式

策略模式(Strategy)的定义:定义一系列算法,将每个算法进行封装,使其能够灵活替换。当算法变化时,使用者无需更改系统的内部实现,这就是策略模式。策略模式属于行为型模式,在实际项目中应用较为广泛。

在合适的场景使用策略模式能够大量减少if else的产生,能够让你的项目具备更加良好的拓展性和可读性。

策略模式的结构

  1. 抽象策略(Strategy):定义一个公共接口,不同策略方法可以实现这个接口。同时这个接口将被上下文(Context)类进行调用,以决策不同算法模型。
  2. 具体策略(ConcreteStrategy):实现了抽象策略中定义的接口,提供具体实现。
  3. 上下文(Context):上下文类即环境类,它管理一个策略类(Strategy)的引用,客户端将调用Context提供的方法以访问策略模式。

策略模式的实际应用场景

  • 支付场景:一个应用同时支持微信支付、支付宝支付、银行卡支付...这类场景可以使用策略模式实现。
  • 生成唯一ID的场景:如UUID生成、雪花算法、用户Token生成...
  • 购物时优惠券的发放:购物时通常优惠券会使用多种方式进行发放,最常见的就是直减优惠,也有满减优惠或者直接打折的方案。

在以上场景中,如果开发者都选择使用if else来判断用户选择的类型,那么程序将臃肿并且难以维护。所以使用策略模式能够很好地解决这些问题。

示例

接下来,我们以购物的优惠券发放作为例子详细讲解策略模式的实现。在本例中,我们将定义三种优惠券:直减优惠券,满减优惠券,打折优惠券。用户可以自行选择使用哪种优惠券进行购物。

首先,我们定义一个抽象策略类。抽象策略类中包含一个打折方法,以供具体策略类实现和上下文进行管理。

Strategy.java

package com.yeliheng.strategy;

/**
 * 抽象策略
 */
public interface Strategy {
    public long discount(long price); // 策略方法
}

接着我们定义三个具体策略类,分别是直减策略、满减策略、折扣策略。

直减策略类:

MinusStrategy.java

package com.yeliheng.strategy;

/**
 * 直减策略
 */
public class MinusDiscount implements Strategy{

    private final long amount = 100; // 直减100元

    @Override
    public long discount(long price) {
        return price - amount;
    }
}

直减策略类直接减去100元,返回最终价格。

满减策略类:

FullReductionDiscount.java

package com.yeliheng.strategy;

/**
 * 满减策略
 */
public class FullReductionDiscount implements Strategy{

    private final long count = 1000; //满1000

    private final long amount = 100; //满减金额

    @Override
    public long discount(long price) {

        if(price > count) {
            return price - amount;
        } else {
           return price;
        }
    }
}

满减策略类中,对金额进行判断,若金额大于设定的1000元门槛,则减去满减金额100元,并返回最终价格。

折扣策略类:

BucklingDiscount.java

package com.yeliheng.strategy;

/**
 * 折扣策略
 */
public class BucklingDiscount implements Strategy{

    private final long discount = 8;

    //为了演示简单,直接省去小数,使用long类型。实际项目切忌这样使用。
    @Override
    public long discount(long price) {
        return (long) (price * discount * 0.1);
    }
}

折扣策略类直接返回原价的8折。

完成了抽象策略类和具体策略类,我们定义Context类,即上下文类来对我们的策略环境进行管理。

Context.java

package com.yeliheng.strategy;

public class Context {

    private Strategy strategy;

    public Strategy getStrategy() {
        return strategy;
    }

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public void discount(long price) {
        System.out.println("折后价格:" + strategy.discount(price));
    }
}

在Context类中,提供了Strategy对象的set get 方法,并定义了discount打折方法,输出具体策略类计算后的价格。

最后,我们就可以在main函数中使用写好的策略模式了。

Main.java

package com.yeliheng.strategy;

public class Main {

    private static final long price = 2000; // 商品价格

    public static void main(String[] args) {

        Context context = new Context();

        System.out.println("[直减策略] 商品原价:" + price);
        Strategy strategy = new MinusDiscount();
        context.setStrategy(strategy);
        context.discount(price);

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

        System.out.println("[满减策略] 商品原价:" + price);
        strategy = new FullReductionDiscount();
        context.setStrategy(strategy);
        context.discount(price);

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

        System.out.println("[折扣策略] 商品原价:" + price);
        strategy = new BucklingDiscount();
        context.setStrategy(strategy);
        context.discount(price);
    }
}

在Main类中,我们依次对三种商品优惠券策略进行调用,运行结果如下图所示:

output.png

三种策略均正确输出。

在本例中,我们使用策略模式减少了if else的调用,使代码的逻辑更加清晰。什么时候选择什么策略,不再需要通过一堆逻辑判断语句,而是通过策略类交给一个上下文类来进行统一地管理。

策略模式的优缺点

优点

  • 使用策略模式能大大减少多重条件语句的使用,优化逻辑结构,提升项目的可维护性。
  • 策略模式提供一系列可复用的解决方法,能够减少重复代码的产生。
  • 策略模式遵循开闭原则,能够在不修改原来代码的情况下增加新的策略。
  • 策略模式能够灵活应对复杂算法场景下产生的逻辑问题。
  • 策略模式使用一个Context上下文类进行策略环境的管理,有利于定义和实现的分离。

缺点

  • 过度使用策略模式会造成策略类的增长,增加系统复杂度。

总结

策略模式是一种使用广泛的设计模式之一,正确理解和使用策略模式能够提升系统的可拓展性和可维护性。本文通过购物优惠券的应用示例详细讲解策略模式的应用。

本文示例的完整源代码参见:Github

Java设计模式行为型模式
2025 © Yeliheng的技术小站 版权所有