作用是应用于同种业务多种情况处理的场景
以下代码实现中的业务场景:目的是获取通道与TradeName的关联关系,通道是一个业务对象,TradeName是一个业务字段,通道与TradeName一对多,每一个通道都关联了TradeName,每个通道下获取TradeName的数据来源处理都不一样。
故适用于策略模式,极大程度上降低各个通道的耦合程度,后续新增通道就新增策略实现类,完全不会影响到历史代码逻辑,外部的调用也不用care策略内部具体的实现逻辑。
但是不要过度设计,这种模式多适用于可预见的大场景、多场景或需重构的业务环境下,简单且几乎不迭代的业务不建议用。
代码实现
Spring上下文对象
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
@Slf4j
@Component
@Lazy(value = false)
public class SpringContextBean implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringContextBean.applicationContext == null) {
SpringContextBean.applicationContext = applicationContext;
}
}
/**
* 获取applicationContext
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 通过name获取 Bean.
*/
public static Object getBean(String name) {
if (!getApplicationContext().containsBean(name)) {
return null;
}
return getApplicationContext().getBean(name);
}
/**
* 通过class获取Bean.
*/
public static <T> T getBean(Class<T> clazz) {
try {
return getApplicationContext().getBean(clazz);
} catch (BeansException e) {
return null;
}
}
/**
* 通过name,以及Clazz返回指定的Bean
*/
public static <T> T getBean(String name, Class<T> clazz) {
if (!getApplicationContext().containsBean(name)) {
return null;
}
return getApplicationContext().getBean(name, clazz);
}
/**
* 通过name获取 Bean.
*/
public static Object getProperty(String key) {
ApplicationContext context = getApplicationContext();
if (ObjectUtils.isEmpty(context)) {
return null;
}
return context.getEnvironment().getProperty(key);
}
/**
* 通过name获取 Bean.
*/
public static String getProfileActive() {
return getProperty("spring.profiles.active", String.class);
}
/**
* 通过name获取 Bean.
*/
public static String getProperty(String key, String defaultValue) {
ApplicationContext context = getApplicationContext();
if (ObjectUtils.isEmpty(context)) {
return null;
}
return context.getEnvironment().getProperty(key, defaultValue);
}
public static <T> T getProperty(String key, Class<T> targetType) {
ApplicationContext context = getApplicationContext();
if (ObjectUtils.isEmpty(context)) {
return null;
}
return context.getEnvironment().getProperty(key, targetType);
}
}
业务代码
客户端
/**
* 通过 tradeName 获取通道信息
*
* @param tradeName tradeName
* @return 通道信息
*/
@Override
public List<InstituteTradeNameResp> getInstituteByTradeName(String tradeName) {
List<InstituteTradeNameResp> allTradeNameList = getAllInstituteTradeName();
// TODO 业务处理
return allTradeNameList;
}
/**
* 获取所有通道与tradeName的映射数据
*
* @return 所有通道与tradeName的映射数据
*/
private List<InstituteTradeNameResp> getAllInstituteTradeName() {
List<InstituteTradeNameResp> list = new ArrayList<>();
// 创建上下文
InstituteTradeNameContext context = new InstituteTradeNameContext();
// 根据策略执行行为
InstituteTradeNameStrategy alipayStrategy = InstituteTradeNameFactoryManager.getStrategy(InstituteTradeNameStrategyConst.ALIPAY_WEB_PAYMENT);
context.setInstituteTradeNameStrategy(alipayStrategy);
List<InstituteTradeNameResp> aliList = context.execute();
InstituteTradeNameStrategy dragonPayStrategy = InstituteTradeNameFactoryManager.getStrategy(InstituteTradeNameStrategyConst.DRAGON_PAY_GCASH_WEB_PAY);
context.setInstituteTradeNameStrategy(dragonPayStrategy);
List<InstituteTradeNameResp> dragonPayList = context.execute();
list.addAll(aliList);
list.addAll(dragonPayList);
return list;
}
工厂管理类
封装工厂类
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 通过tradeName确认通道的简单工厂管理类 - 注册工厂并创建策略对象
*
* @author jiangXueZhi
* @date 2024/5/21
*/
@Slf4j
@Component
public class InstituteTradeNameFactoryManager {
@Resource
private List<InstituteTradeNameFactory> instituteTradeNameStrategyList;
private static Map<String, InstituteTradeNameFactory> factoryMap = new HashMap<>();
/**
* 手动注册工厂
*
* @param instituteName 通道名称 - 决定注册到哪个工厂实现中
* @param factory 工厂实现类
*/
public void registerFactory(String instituteName, InstituteTradeNameFactory factory) {
factoryMap.put(instituteName, factory);
}
/**
* 自动注册工厂
*/
@PostConstruct // 该注解类似于静态代码块,启动项会自动执行
public void initRegisterFactory() {
factoryMap = instituteTradeNameStrategyList.stream().collect(Collectors.toMap(InstituteTradeNameFactory::initStrategyKey, Function.identity())); // 调用各个实现类的initStrategyKey方法获取数据
}
/**
* 创建策略接口对象
*
* @param instituteName 通道名称
* @return 策略接口对象
*/
public static InstituteTradeNameStrategy getStrategy(String instituteName) {
InstituteTradeNameFactory instituteTradeNameFactory = factoryMap.get(instituteName);
if (ObjectUtils.isEmpty(instituteTradeNameFactory)) {
log.warn("InstituteTradeNameFactoryManager, createStrategy, instituteTradeNameFactory is empty, instituteName : {}, factoryMapKey : {}", instituteName, factoryMap.keySet());
return null;
}
return instituteTradeNameFactory.createStrategy();
}
}
工厂
创建策略对象
/**
* 通过tradeName确认通道的简单工厂类
*/
public interface InstituteTradeNameFactory {
/**
* 策略key, 用来获取不同的工厂
*/
String initStrategyKey();
InstituteTradeNameStrategy createStrategy();
}
工厂实现
创建对应不同行为的策略对象
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* Alipay - Web Payment 工厂实现
*/
@Slf4j
@Service
public class InstituteTradeNameFactoryAlipayWebPayment implements InstituteTradeNameFactory{
@Override
public String initStrategyKey() {
return InstituteTradeNameStrategyConst.ALIPAY_WEB_PAYMENT;
}
/**
* 创建策略对象 Alipay - Web Payment
*/
@Override
public InstituteTradeNameStrategy createStrategy() {
// return new InstituteTradeNameStrategyAlipayWebPayment(); 此处设计的不好 策略实现中强依赖了Spring 如果用new的话会导致注入进来的对象是null
return SpringContextBean.getBean(InstituteTradeNameStrategy.class);
}
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* DragonPay - GCash-Web Pay 工厂实现
*/
@Slf4j
@Service
public class InstituteTradeNameFactoryDragonPay implements InstituteTradeNameFactory{
@Override
public String initStrategyKey() {
return InstituteTradeNameStrategyConst.DRAGON_PAY_GCASH_WEB_PAY;
}
/**
* 创建策略对象 DragonPay - GCash-Web Pay
*/
@Override
public InstituteTradeNameStrategy createStrategy() {
// return new InstituteTradeNameStrategyDragonPay(); 此处设计的不好 策略实现中强依赖了Spring 如果用new的话会导致注入进来的对象是null
return SpringContextBean.getBean(InstituteTradeNameStrategy.class);
}
}
策略
同种业务
import java.util.List;
/**
* 通过tradeName确认通道的策略
*/
public interface InstituteTradeNameStrategy {
/**
* 行为
*
* @return tradeName 对应的通道
*/
List<InstituteTradeNameResp> getInstituteWithTradeName();
}
策略行为实现
不同行为
import com.beust.jcommander.internal.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
/**
* Alipay - Web Payment 策略实现
*
* @author jiangXueZhi
* @date 2024/5/20
*/
@Slf4j
@Service
public class InstituteTradeNameStrategyAlipayWebPayment implements InstituteTradeNameStrategy{
@Override
public List<InstituteTradeNameResp> getInstituteWithTradeName() {
InstituteTradeNameResp resp = new InstituteTradeNameResp();
resp.setInstituteId(1);
resp.setInstituteName("Alipay - Web Payment");
resp.setTradeName("Alipay TradeName");
return Collections.singletonList(resp);
}
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
/**
* DragonPay - GCash-Web Pay 策略实现
*
* @author jiangXueZhi
* @date 2024/5/20
*/
@Slf4j
@Service
public class InstituteTradeNameStrategyDragonPay implements InstituteTradeNameStrategy{
@Override
public List<InstituteTradeNameResp> getInstituteWithTradeName() {
InstituteTradeNameResp resp = new InstituteTradeNameResp();
resp.setInstituteId(1);
resp.setInstituteName("DragonPay - GCash-Web Pay");
resp.setTradeName("DragonPay TradeName");
return Collections.singletonList(resp);
}
}
上下文
进一步封装
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
/**
* 通过tradeName确认通道的上下文
*
* @author jiangXueZhi
* @date 2024/5/21
*/
@Slf4j
@Setter
public class InstituteTradeNameContext {
private InstituteTradeNameStrategy instituteTradeNameStrategy;
public List<InstituteTradeNameResp> execute() {
if (instituteTradeNameStrategy == null) {
return new ArrayList<>();
}
return instituteTradeNameStrategy.getInstituteWithTradeName();
}
}
行为种类
方便行为的管理
import lombok.Getter;
@Getter
public class InstituteTradeNameStrategyConst {
/**
* Alipay - Web Payment
*/
public static final String ALIPAY_WEB_PAYMENT = "Alipay - Web Payment";
/**
* AllBank - QR DragonPay - GCash-Web Pay
*/
public static final String ALL_BANK_QR = "Allbank - QR";
}
业务响应
{
"code": 1,
"data": [
{
"institute_id": 1,
"institute_name": "Alipay - Web Payment",
"trade_name": "Alipay TradeName"
},
{
"institute_id": 1,
"institute_name": "DragonPay - GCash-Web Pay",
"trade_name": "DragonPay TradeName"
}
],
"message": "success"
}
根据资料整理的流程图
资料地址:工厂模式和策略模式区别以及使用_策略模式和工厂模式的区别-CSDN博客