一、策略模式介绍

1. 解决的问题

主要解决多种算法类似的情况下,使用条件语句所带来的复杂和难以维护。

2. 定义

策略模式是一种行为设计模式,它能让你定义一系列算法,并将每种算法分别放入独立的类中,以使算法的对象能够相互替换。

3. 应用场景
  • 当想使用对象中各种不同的算法变体,并希望能在运行时切换算法时,可使用策略模式。
  • 当有许多仅在执行某些行为时略有不同的相似类时,可使用策略模式。
  • 如果算法在上下文的逻辑中不是特别重要,使用策略模式能将类的业务逻辑与其算法实现细节隔离开来。
  • 当类中使用了复杂条件运算符以在同一算法的不同变体中切换时,可使用策略模式。

二、策略模式优缺点

1. 优点
  • 可以在运行时切换对象的算法。
  • 可以将算法的实现和使用算法的代码隔离开来。
  • 可以使用组合来代替继承。
  • 开闭原则:无需对上下文进行修改就能够引入新的策略。
2. 缺点
  • 如果算法极少发生改变,那么没必要引入新的类和接口。使用策略模式只会让程序过于复杂。
  • 客户端必须知晓策略间的不同,因为客户端要选择合适的策略。
  • 许多语言支持函数类型功能,允许在一组匿名函数中实现不同版本的算法。这样,使用这些函数的方式就和使用策略对象完全相同,无需借助额外的类和接口来保持代码简洁。

三、策略模式应用实例:SpringBoot 优雅实现策略模式

1. 实例场景

618已经来临,相信大家都已经开始了买买买的囤货模式,加入购物车,点击支付,选择微信、支付宝、或者银行卡就可以顺利买到自己心仪已久的特促。

今天,就支付选择策略为例,讲一下如何使用 SpringBoot 优雅实现策略模式。

2. 状态模式实现
2.1 工程结构
strategy-pattern
└─ src
    ├─ main
    │	└─ java
    │    └─ org.design.pattern.strategy
    │       ├─ service
    │       │    ├─ PayService.java
    │       │    └─ impl
    │       │    	├─ AliPayServiceImpl.java
    │       │    	├─ WeChatPayServiceImpl.java
    │       │    	└─ BandCardPayServiceImpl.java
    │       └─ context
    │            └─ PayServiceContext.java
    └─ test
    	└─ java
            └─ org.design.pattern.strategy
      			└─ PayServiceTest.java
2.2 代码实现
2.2.1 服务类

支付服务接口

/**
 * 支付服务接口
 */
public interface PayService {

    /**
     * 支付账单
     *
     * @param billAmount 账单金额
     */
    void payBill(Integer billAmount);
}

支付宝支付服务实现类

/**
 * 支付宝支付服务实现类
 */
@Slf4j
@Service("AliPayService")
public class AliPayServiceImpl implements PayService {

    /**
     * 支付账单
     *
     * @param billAmount 账单金额
     */
    @Override
    public void payBill(Integer billAmount) {
        log.info("支付宝支付:您已支付{}元,请确认是否为本人操作", billAmount);
    }
}

微信支付服务实现类

/**
 * 微信支付服务实现类
 */
@Slf4j
@Service("WeChartPayService")
public class WeChatPayServiceImpl implements PayService {

    /**
     * 支付账单
     *
     * @param billAmount 账单金额
     */
    @Override
    public void payBill(Integer billAmount) {
        log.info("微信支付:您已支付{}元,请确认是否为本人操作", billAmount);
    }
}

银行卡支付服务实现类

/**
 * 银行卡支付服务实现类
 */
@Slf4j
@Service("BankCardPayService")
public class BandCardPayServiceImpl implements PayService {

    /**
     * 支付账单
     *
     * @param billAmount 账单金额
     */
    @Override
    public void payBill(Integer billAmount) {
        log.info("银行卡支付:您已支付{}元,余额1000元,请确认是否为本人操作", billAmount);
    }
}
2.2.2 上下文

支付服务Context

/**
 * 支付服务Context
 */
@Component
public class PayServiceContext {

    /**
     * 支付服务map
     */
    @Autowired
    private final Map<String, PayService> strategyPayServiceMap = new ConcurrentHashMap<>();

    /**
     * 获取支付服务
     *
     * @param id 服务id
     * @return PayService
     */
    public PayService getPayService(String id) {
        PayService payService = this.strategyPayServiceMap.get(id);
        if (ObjectUtils.isEmpty(payService)) {
            throw new IllegalArgumentException("no such " + id + " PayService");
        }
        return payService;
    }
}
2.3 测试验证
2.3.1 测试验证类
@SpringBootTest
@RunWith(SpringRunner.class)
public class PayServiceTest {

    /**
     * 支付服务Context
     */
    @Autowired
    private PayServiceContext payServiceContext;

    @Test
    public void test() {
        // 微信支付
        this.payServiceContext.getPayService("WeChartPayService").payBill(100);
        // 支付宝支付
        this.payServiceContext.getPayService("AliPayService").payBill(200);
        // 银行卡支付
        this.payServiceContext.getPayService("BankCardPayService").payBill(300);
    }
}
2.3.2 测试结果
2021-06-06 14:38:11.045  INFO 7652 --- [           main] o.d.p.s.s.impl.WeChatPayServiceImpl      : 微信支付:您已支付100元,请确认是否为本人操作
2021-06-06 14:38:11.047  INFO 7652 --- [           main] o.d.p.s.service.impl.AliPayServiceImpl   : 支付宝支付:您已支付200元,请确认是否为本人操作
2021-06-06 14:38:11.047  INFO 7652 --- [           main] o.d.p.s.s.impl.BandCardPayServiceImpl    : 银行卡支付:您已支付300元,余额1000元,请确认是否为本人操作

四、策略模式结构

java 策略模式怎么调用 java实现策略模式_java

  1. 上下文(Context)维护执行具体策略的引用,仅通过策略接口与该对象进行交流。
    当上下文需要运行算法时,它会在其已连接的策略对象上调用执行方法。上下文不清楚其所涉及的策略类型与算法的执行方式。
  2. 策略(Strategy)接口是所有具体策略的通用接口,它声明了一个上下文用于执行策略的方法。
  3. 具体策略(Concrete Strategies)实现了上下文所用算法的各种不同变体。
  4. 客户端(Client)会创建一个特定策略对象并将其传递给上下文。上下文则会提供一个设置器以便客户端在运行时替换相关联的策略。

设计模式并不难学,其本身就是多年经验提炼出的开发指导思想,关键在于多加练习,带着使用设计模式的思想去优化代码,就能构建出更合理的代码。