以不同平台(tt,wx,hy)发放刷视频奖励为例,包括用户认证 ->绑定银行卡->风险校验->发放奖励 这些步骤进行案例讲述。
策略模式一般是通过定义接口去扩展一类行为(算法),通过不同的实现类达到行为的多样化。(所有实现类称为算法镞)
本例中段视频平台发放奖励这一行为就可理解为是一个算法,而不同平台的发放方式就构成了算法镞。
所以我们先定义一个发放策略的接口。
public interface AwardStrategy {
/**
* 获取发放来源.
* @return 发放来源
*/
String getSource();
/**
* 发放奖品.
* @return 是否成功发放
*/
Boolean award(String userId);
}
定义一个平台枚举类用来维护平台信息。
public enum AwardSourceEnum {
/**
* tt
*/
TOUTIAO,
/**
*hy
*/
HUYA,
/**
* wx
*/
WEIXIN
}
不同的平台实现这个接口,代码后面会贴出来。
对于 用户认证 ->绑定银行卡->风险校验->发放奖励 这类统一的步骤与其在每个实现类中自己去定义流程步骤不如在父类定义为一个流程模版,不同的实现类去实现模版方法中调用的每个子步骤即可实现定制化流程的效果,这样就不用每个实现类都要维护流程顺序,当流程发生变化时在父类中修改即可。
新建模版方法抽象类:
@Slf4j
public abstract class BaseAwardService {
/**
* 发放奖励模版方法
*/
protected Boolean awardTemplate(String userId) {
authentication(userId);
bindBankCard();
risk();
return awardRecord();
}
protected void risk() {
log.info("------系统风险检查-------");
}
protected Boolean awardRecord() {
log.info("--------执行默认的奖励发放-------");
return Boolean.TRUE;
}
protected void bindBankCard() {
log.info("--------绑定银行卡-------");
}
protected void authentication(String userId) {
log.info("--------认证-------");
}
}
每个子类去继承这个父类并重写模版方法的子步骤:
tt平台:
@Service
@Slf4j
public class ToutiaoAwardStrategyService extends BaseAwardService implements AwardStrategy{
@Override
public String getSource() {
return AwardSourceEnum.TOUTIAO.name();
}
@Override
public Boolean award(String userId) {
return super.awardTemplate(userId);
}
@Override
protected void risk() {
super.risk();
log.info("------头条风控检查------");
}
@Override
protected Boolean awardRecord() {
super.awardRecord();
log.info("--------头条发放奖励------");
return Boolean.TRUE;
}
@Override
protected void bindBankCard() {
super.bindBankCard();
log.info("-------在头条绑定银行卡------------");
}
@Override
protected void authentication(String userId) {
super.authentication(userId);
log.info("-------userId:{} 在头条认证------------",userId);
}
}
hy平台:
@Service
@Slf4j
public class HuYaAwardStrategyService extends BaseAwardService implements AwardStrategy{
@Override
public String getSource() {
return AwardSourceEnum.HUYA.name();
}
@Override
public Boolean award(String userId) {
return super.awardTemplate(userId);
}
@Override
protected void risk() {
super.risk();
log.info("------hy风控检查------");
}
@Override
protected Boolean awardRecord() {
super.awardRecord();
log.info("--------hy发放奖励------");
return Boolean.TRUE;
}
@Override
protected void bindBankCard() {
super.bindBankCard();
log.info("-------在hy绑定银行卡------------");
}
@Override
protected void authentication(String userId) {
super.authentication(userId);
log.info("-------userId:{} 在hy认证------------",userId);
}
}
wx平台:
@Service
@Slf4j
public class WXAwardStrategyService extends BaseAwardService implements AwardStrategy{
@Override
public String getSource() {
return AwardSourceEnum.WEIXIN.name();
}
@Override
public Boolean award(String userId) {
return super.awardTemplate(userId);
}
@Override
protected void risk() {
super.risk();
log.info("------wx风控检查------");
}
@Override
protected Boolean awardRecord() {
super.awardRecord();
log.info("--------wx发放奖励------");
return Boolean.TRUE;
}
@Override
protected void bindBankCard() {
super.bindBankCard();
log.info("-------在wx绑定银行卡------------");
}
@Override
protected void authentication(String userId) {
super.authentication(userId);
log.info("-------userId:{} 在wx认证------------",userId);
}
}
使用工厂方法去获取对应平台的发放服务。
public class AwardServiceFactory {
private final static Map<String, AwardStrategy> MAP=new HashMap<>(8);
static {
Map<String, AwardStrategy> beansOfType = SpringUtil.getBeansOfType(AwardStrategy.class);
beansOfType.values().forEach(awardStrategy -> MAP.put(awardStrategy.getSource(),awardStrategy));
}
private AwardServiceFactory(){}
/**
* 对外统一暴露的工厂方法
*/
public static AwardStrategy getAwardService(String source) {
AwardStrategy strategy = MAP.get(source);
if (Objects.isNull(strategy)) {
throw new RuntimeException("渠道异常!");
}
return strategy;
}
}
springUtil: 获取容器bean的工具类
@Component
public class SpringUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringUtil.applicationContext == null) {
SpringUtil.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> Map<String, T> getBeansOfType(Class<T> clazz) {
return getApplicationContext().getBeansOfType(clazz);
}
/**
*通过type 拿到所有该类型的map集合 key:beanName value:bean
*/
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
/**
* 获取配置文件配置项的值
*
* @param key 配置项key
*/
public static String getEnvironmentProperty(String key) {
return getApplicationContext().getEnvironment().getProperty(key);
}
/**
* 获取spring.profiles.active
*/
public static String getActiveProfile() {
return getApplicationContext().getEnvironment().getActiveProfiles()[0];
}
}
测试类:
@Test
void award() {
//tt 平台
AwardStrategy awardService = AwardServiceFactory.getAwardService(AwardSourceEnum.TOUTIAO.name());
awardService.award("张三");
//hy平台
AwardStrategy awardService2 = AwardServiceFactory.getAwardService(AwardSourceEnum.HUYA.name());
awardService2.award("李四");
//wx平台
AwardStrategy awardService3 = AwardServiceFactory.getAwardService(AwardSourceEnum.WEIXIN.name());
awardService3.award("赵六");
}
这样就实现了通过设计模式减少业务代码的if-else。