介绍:
Strategy 模式和 Template 模式要解决的问题是相同(类似)的,都是为了给业务逻辑(算法)具体实现和抽象接口之间的解耦。Strategy 模式将逻辑(算法)封装到一个类(Context) 里面,通过组合的方式将具体算法的实现在组合对象中实现,再通过委托的方式将抽象接口 的实现委托给组合对象实现。
结构图:
策略模式的优缺点:
优点:
算法可以自由切换(高层屏蔽算法,角色自由切换)
避免使用多重条件判断(如果算法过多就会出现很多种相同的判断,很难维护)
扩展性好(可自由添加取消算法 而不影响整个功能)
缺点:
策略类数量增多(每一个策略类复用性很小,如果需要增加算法,就只能新增类)
所有的策略类都需要对外暴露(使用的人必须了解使用策略,这个就需要其它模式来补充,比如工厂模式、代理模式)
代码:
代码结构:
Maven依赖:
<dependencies>
<!-- sprinboot web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<!-- mysql 依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
PayController
package com.ldq.controller;
import com.ldq.strategy.context.PayContextStrategy;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Auther: liangdeqiang
* @Date: 2019-5-12 14:19
* @Description:
*/
@RestController
public class PayController {
@Autowired
private PayContextStrategy payContextStrategy;
@RequestMapping("/toPayHtml")
public String toPayHtml(String payCode){
if(StringUtils.isEmpty(payCode)){
return "payCode不能为空";
}
return payContextStrategy.toPayHtml(payCode);
}
}
PaymentChannelEntity
package com.ldq.mapper.entity;
import lombok.Data;
@Data
public class PaymentChannelEntity {
/** ID */
private Integer id;
/** 渠道名称 */
private String channelName;
/** 渠道ID */
private String channelId;
/**
* 策略执行beanId
*/
private String strategyBeanId;
}
PaymentChannelMapper
package com.ldq.mapper;
import com.ldq.mapper.entity.PaymentChannelEntity;
import org.apache.ibatis.annotations.Select;
public interface PaymentChannelMapper {
@Select("\n" +
"SELECT id as id ,CHANNEL_NAME as CHANNELNAME ,CHANNEL_ID as CHANNELID,strategy_bean_id AS strategybeanid\n" +
"FROM payment_channel where CHANNEL_ID=#{payCode}")
public PaymentChannelEntity getPaymentChannel(String payCode);
}
PayContextStrategy
package com.ldq.strategy.context;
import com.ldq.mapper.PaymentChannelMapper;
import com.ldq.mapper.entity.PaymentChannelEntity;
import com.ldq.strategy.PayStrategy;
import com.ldq.utils.SpringUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @Auther: liangdeqiang
* @Date: 2019-5-12 14:08
* @Description:
*/
@Service
public class PayContextStrategy {
@Autowired
private PaymentChannelMapper paymentChannelMapper;
@Autowired
private SpringUtils springUtils;
public String toPayHtml(String payCode){
//1.通过payCode查询数据库获取beanId
PaymentChannelEntity paymentChannel = paymentChannelMapper.getPaymentChannel(payCode);
if(paymentChannel == null){
return "没有该渠道信息";
}
//2.获取beanId之后,从springboot容器中获取实例对象
String strategyBeanId = paymentChannel.getStrategyBeanId();
if(StringUtils.isEmpty(strategyBeanId)){
return "该渠道未配置beanId";
}
PayStrategy payStrategy = springUtils.getBean(strategyBeanId, PayStrategy.class);
// 3.执行该实现的方法即可....
return payStrategy.toPayHtml();
}
}
AliPayStrategy
package com.ldq.strategy.impl;
import com.ldq.strategy.PayStrategy;
import org.springframework.stereotype.Component;
/**
* @Auther: liangdeqiang
* @Date: 2019-5-12 14:08
* @Description:
*/
@Component
public class AliPayStrategy implements PayStrategy {
@Override
public String toPayHtml() {
return "调用支付宝支付接口...";
}
}
YinLianPayStrategy
package com.ldq.strategy.impl;
import com.ldq.strategy.PayStrategy;
import org.springframework.stereotype.Component;
/**
* @Auther: liangdeqiang
* @Date: 2019-5-12 14:10
* @Description:
*/
@Component
public class YinLianPayStrategy implements PayStrategy {
@Override
public String toPayHtml() {
return "调用银联支付接口...";
}
}
PayStrategy
package com.ldq.strategy;
/**
* @Auther: liangdeqiang
* @Date: 2019-5-12 14:06
* @Description:
*/
public interface PayStrategy {
/**
* 策略模式共同算法的骨架
*/
String toPayHtml();
}
SpringUtils
package com.ldq.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* 使用beanid 获取spring容器中的对下午那个
*/
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
//获取applicationContext
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//通过name获取 Bean.
public static Object getBean(String name){
return getApplicationContext().getBean(name);
}
//通过class获取Bean.
public static <T> T getBean(Class<T> clazz){
return getApplicationContext().getBean(clazz);
}
//通过name,以及Clazz返回指定的Bean
public static <T> T getBean(String name,Class<T> clazz){
return getApplicationContext().getBean(name, clazz);
}
}
AppStrategy
package com.ldq;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @Auther: liangdeqiang
* @Date: 2019-5-12 14:22
* @Description:
*/
@SpringBootApplication
@MapperScan("com.ldq.mapper")
public class AppStrategy {
public static void main(String[] args) {
SpringApplication.run(AppStrategy.class);
}
}
application.yml
###服务启动端口号 server: port: 8080 spring: ###数据库相关连接 datasource: username: ...... password: ...... driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/design_pattern?useUnicode=true&characterEncoding=UTF-8 ####打印MyBatias日志 logging: level: ### 开发环境使用DEBUG 生产环境info或者error com.ldq.member.mapper: DEBUG
源于:http://www.mayikt.com/