1-定义支付接口
/**
* <简述>支付接口
* <详细描述>
* @author syf
* @date 2023年07月26日 10:00
*/
public interface PayStrategy {
//
public void pay(double money);
}
2-定义支付宝 微信实现类 实现支付接口
/**
* <简述>阿里支付
* <详细描述>
*
* @author syf
* @date 2023年07月26日 10:02
*/
@Service("ali")
public class AliPayStrategy implements PayStrategy {
@Override
public void pay(double money) {
System.out.println(String.format("支付宝支付了:%.2f元", money));
}
}
/**
* <简述>微信支付
* <详细描述>
*
* @author syf
* @date 2023年07月26日 10:03
*/
@Service("wechat")
public class WeChatPayStrategy implements PayStrategy {
@Override
public void pay(double money) {
System.out.println(String.format("微信支付了:%.2f元", money));
}
}
3- 定义一个工厂来存储不同的策略对象
/**
* <简述>定义一个工厂来存储不同的策略对象
* <详细描述>
* @author syf
* @date 2023年07月26日 10:07
*/
@Component
public class PayStrategyFactory {
//ConcurrentHashMap 现成安全的map
private static Map<String, PayStrategy> map = new ConcurrentHashMap<>();
//静态代码块,在类加载的时候执行
static {
map.put("wechat", new WeChatPayStrategy());
map.put("ali", new AliPayStrategy());
}
//通过类型找到策略对象
public static PayStrategy getPayStrategy(String payType){
return map.get(payType);
}
}
4-测试接口
/**
* <简述>
* <详细描述>
*
* @author syf
* @date 2023年07月26日 10:22
*/
@RestController
public class PayController {
@Autowired
private PayStrategyFactory payStrategyFactory;
@GetMapping("/pay/{type}/{money}")
public String pay(@PathVariable("type") String type, @PathVariable("money")double money){
PayStrategy payStrategy = payStrategyFactory.getPayStrategy(type);
if(null == payStrategy){
return "支付类型为空" ;
}
payStrategy.pay(money);
return "成功" ;
}
}
结果展示
支付宝支付了:9999.00元
5 - 延伸 (spring 管理bean)
工厂以及接口对象不应该自己new,最好交由spring管理
改造如下:PayStrategy 接口交由spring管理,实现工厂支付接口
5-1 枚举类
public enum PayTypes {
wechat,ali
}
5-2 工厂类
根据枚举类型获取,支付接口的实例
枚举类
public enum PayTypes {
WE_HCAT("wechat", "微信"),ALI("ali", "阿里");
private String code;
private String name;
PayTypes(String code, String name) {
this.code = code;
this.name = name;
}
public String getCode() {
return code;
}
/***
* <简述>提供对外获取
* <详细描述>
* @author syf
* @date 2023/8/14 10:40
* @param code
* @return com.ratelimiter.enums.PayTypes
*/
public static PayTypes getEnum(String code){
for(PayTypes animal:PayTypes.values()){
if(animal.code.equals(code)){
return animal;
}
}
return null;
}
}
支付实例的工厂类,PayStrategy 接口的实现类交由spring管理,放入map中存储
@Component
public class PayStrategyFactorySprings {
/**
* <简述>PayStrategy接口的实现类交给spring管理
* <详细描述>@Autowired 注解来自动注入所有实现 PayStrategy 接口的 bean
@Qualifier 根据bean名称注入
* @return null
* @author syf
* @date 2023/8/2 23:30
*/
@Autowired
private PayStrategyFactoryNews(@Qualifier("ali") PayStrategy AliPayStrategy, @Qualifier("wechat") PayStrategy WeChatPayStrategy) {
map.put(PayTypes.getEnum("ali").getCode(), AliPayStrategy);
map.put(PayTypes.getEnum("wechat").getCode(), WeChatPayStrategy);
}
//提供对外的方法,可以通过key取到实现类
public PayStrategy getPayStrategy(String type) {
return map.get(type);
}
}
上面是单个bean注入,也可以写成 用list注入 PayStrategy 接口的所有实现类
@Component
public class PayStrategyFactorySprings {
@Autowired
//使用注解注入,要注入的list泛型是接口而不是下边实现类,这样就会自动把次接口下的实现类都注入到list中
private List<PayStrategy> payStrategyList;
//创建hashMap来保存这些实现类,并且调用实现类的getType方法作为key,具体实现类为value(因为spring的BeanFactory时单例模式,所以不用担心会重复创建实现类,实际就是一个引用)
//在外面就可以通过key来获取到对应的实现类,进行不同的动作
private Map<String, PayStrategy> serviceMap = new HashMap<>();
//在项目构建完成时,执行此方法 进行map的赋值
@PostConstruct
public void init() {
//遍历实现类集合,根据循环到的实现类的getType()方法作为key,循环到的实现类zuoweuvalue,方便根据key取到对应实现类
payStrategyList.stream().forEach(a -> {
//@Service("ali") @Service("wechat")
serviceMap.put(a.getClass().getSimpleName() , a);
});
}
//提供对外的方法,可以通过key取到实现类
public PayStrategy getPayStrategy(String type) {
return serviceMap.get(type);
}
}
如图
5-3调试接口
@RestController
@Slf4j
public class PayController {
@Autowired
private PayStrategyFactorySprings payStrategyFactorySprings;
/**
* <简述>工厂交由spring管理
* <详细描述>
* @author syf
* @date 2023/7/26 15:22
* @param type
* @return java.lang.String
*/
@GetMapping("/pay")
public String pay(@RequestParam("type") String type){
//获取接口工厂实例
PayStrategy payStrategy = payStrategyFactorySprings.getPayStrategy(type);
if(null == payStrategy){
return "支付类型为空" ;
}
double money = 9999d;
payStrategy.pay(money);
return "成功" ;
}
}
结果展示:
6- java后台多线程模拟测试接口
引入单元测试类
<!-- Junit 5 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
编写测试类代码 测试接口
@SpringBootTest
public class Test {
MockMvc mockMvc;
@Autowired
private WebApplicationContext wac;
@org.junit.jupiter.api.Test
public void pay() throws Exception{
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
for (int i = 0; i < 10 ;i++){
Thread thread = new Thread(() -> {
try {
int type = new Random().nextInt(2);
double money = new Random().nextInt(100) + 1;
if (type == 0) {
mockMvc.perform(MockMvcRequestBuilders.get("/pay/wechat/" + money));
} else {
mockMvc.perform(MockMvcRequestBuilders.get("/pay/ali/" + money));
}
} catch (Exception e) {
}
}, "用户1" + (i + 1) + "--->");
thread.start();
}
Thread.sleep(5000);
}
}
用户12--->阿里将支付98.0
用户16--->阿里将支付3.0
用户17--->阿里将支付72.0
用户11--->阿里将支付13.0
用户110--->阿里将支付71.0
用户19--->阿里将支付53.0
用户18--->阿里将支付27.0
用户14--->阿里将支付10.0
用户15--->阿里将支付38.0
用户13--->阿里将支付51.0
用户16--->支付宝支付了:3.00元
用户18--->微信支付了:27.00元
用户14--->微信支付了:10.00元
用户15--->微信支付了:38.00元
用户17--->支付宝支付了:72.00元
用户13--->微信支付了:51.00元
用户11--->支付宝支付了:13.00元
用户19--->微信支付了:53.00元
用户110--->微信支付了:71.00元
用户12--->微信支付了:98.00元