设计模式的应用
设计模式的应用
淘票票项目作为高并发的票务系统,在架构设计中广泛应用了多种设计模式,以提高代码的可维护性、可扩展性和复用性。本文将详细介绍项目中使用的主要设计模式及其具体应用。
1. 工厂模式(Factory Pattern)
1.1 模式定义
工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,而是引用一个共同的接口来指向新创建的对象。
1.2 项目应用
1.2.1 ServiceLockFactory(分布式锁工厂)
在分布式锁模块中,ServiceLockFactory根据锁类型创建不同的锁实现:
public class ServiceLockFactory {
private final ManageLocker manageLocker;
public ServiceLocker getLock(LockType lockType){
ServiceLocker lock;
switch (lockType) {
case Fair:
lock = manageLocker.getFairLocker();
break;
case Write:
lock = manageLocker.getWriteLocker();
break;
case Read:
lock = manageLocker.getReadLocker();
break;
default:
lock = manageLocker.getReentrantLocker();
break;
}
return lock;
}
}1.2.2 LockInfoHandleFactory(锁信息处理器工厂)
LockInfoHandleFactory通过Spring容器获取不同类型的锁信息处理器:
public class LockInfoHandleFactory implements ApplicationContextAware {
private ApplicationContext applicationContext;
public LockInfoHandle getLockInfoHandle(String lockInfoType){
return applicationContext.getBean(lockInfoType, LockInfoHandle.class);
}
}1.2.3 CaptchaServiceFactory(验证码服务工厂)
CaptchaServiceFactory使用Java SPI机制加载所有验证码服务实现:
public class CaptchaServiceFactory {
static {
ServiceLoader<CaptchaService> services = ServiceLoader.load(CaptchaService.class);
for (CaptchaService item : services) {
instances.put(item.captchaType(), item);
}
}
public static CaptchaService getInstance(Properties config) {
String captchaType = config.getProperty(Const.CAPTCHA_TYPE, "default");
CaptchaService ret = instances.get(captchaType);
// ...
return ret;
}
}2. 策略模式(Strategy Pattern)
2.1 模式定义
策略模式是一种行为设计模式,它能让你定义一系列算法,并将每种算法分别放入独立的类中,使算法的变化独立于使用它们的客户端。
2.2 项目应用
2.2.1 支付策略
在支付服务中,项目通过策略模式支持多种支付方式:
- PayStrategyHandler定义支付策略接口:
public interface PayStrategyHandler {
PayResult pay(String outTradeNo, BigDecimal price, String subject, String notifyUrl, String returnUrl);
boolean signVerify(Map<String, String> params);
boolean dataVerify(Map<String, String> params, PayBill payBill);
TradeResult queryTrade(String outTradeNo);
RefundResult refund(String outTradeNo, BigDecimal price, String reason);
String getChannel();
}- AlipayStrategyHandler实现支付宝支付策略:
public class AlipayStrategyHandler implements PayStrategyHandler {
@Override
public PayResult pay(String outTradeNo, BigDecimal price, String subject, String notifyUrl, String returnUrl) {
// 支付宝支付具体实现
}
@Override
public String getChannel() {
return PayChannel.ALIPAY.getValue();
}
// 其他方法实现...
}- PayStrategyContext管理支付策略:
public class PayStrategyContext {
private final Map<String,PayStrategyHandler> payStrategyHandlerMap = new HashMap<>();
public void put(String channel,PayStrategyHandler payStrategyHandler){
payStrategyHandlerMap.put(channel,payStrategyHandler);
}
public PayStrategyHandler get(String channel){
return Optional.ofNullable(payStrategyHandlerMap.get(channel)).orElseThrow(
() -> new TaoPiaoPiaoFrameException(BaseCode.PAY_STRATEGY_NOT_EXIST));
}
}- PayStrategyInitHandler负责策略初始化和注册:
@AllArgsConstructor
public class PayStrategyInitHandler extends AbstractApplicationInitializingBeanHandler {
private final PayStrategyContext payStrategyContext;
@Override
public Integer executeOrder() {
return 1;
}
@Override
public void executeInit(ConfigurableApplicationContext context) {
Map<String, PayStrategyHandler> payStrategyHandlerMap = context.getBeansOfType(PayStrategyHandler.class);
for (Entry<String, PayStrategyHandler> entry : payStrategyHandlerMap.entrySet()) {
PayStrategyHandler payStrategyHandler = entry.getValue();
payStrategyContext.put(payStrategyHandler.getChannel(),payStrategyHandler);
}
}
}2.2.2 订单创建策略
在节目订单服务中,项目通过策略模式支持多个版本的订单创建逻辑:
- ProgramOrderStrategy定义订单创建策略接口:
public interface ProgramOrderStrategy {
String createOrder(ProgramOrderCreateDto programOrderCreateDto);
}- ProgramOrderContext管理订单策略并实现策略选择逻辑:
public class ProgramOrderContext {
/**
* 存储版本号与对应策略实现的映射关系
* key: 版本号
* value: 对应的节目订单策略实现
*/
private static final Map<String,ProgramOrderStrategy> MAP = new HashMap<>(8);
/**
* 添加指定版本的节目订单策略实现到上下文映射中
* @param version 版本号
* @param programOrderStrategy 节目订单策略实现
*/
public static void add(String version,ProgramOrderStrategy programOrderStrategy){
MAP.put(version,programOrderStrategy);
}
/**
* 根据版本号获取对应的节目订单策略实现
* @param version 版本号
* @return 对应的节目订单策略实现
* @throws TaoPiaoPiaoFrameException 当找不到对应版本的策略实现时抛出异常
*/
public static ProgramOrderStrategy get(String version){
return Optional.ofNullable(MAP.get(version)).orElseThrow(() ->
new TaoPiaoPiaoFrameException(BaseCode.PROGRAM_ORDER_STRATEGY_NOT_EXIST));
}
}- 不同版本的实现类,每个实现类会在初始化时将自身注册到ProgramOrderContext中:
- ProgramOrderV1Strategy
- ProgramOrderV2Strategy - 继承了AbstractApplicationCommandLineRunnerHandler用于初始化时注册
- ProgramOrderV3Strategy
- ProgramOrderV4Strategy
- 控制器中根据接口版本调用不同策略实现:
@RestController
@RequestMapping("/program/order")
public class ProgramOrderController {
@Operation(summary = "购票V1")
@PostMapping(value = "/create/v1")
public ApiResponse<String> createV1(@Valid @RequestBody ProgramOrderCreateDto programOrderCreateDto) {
return ApiResponse.ok(ProgramOrderContext.get(ProgramOrderVersion.V1_VERSION.getVersion())
.createOrder(programOrderCreateDto));
}
@Operation(summary = "购票V2")
@PostMapping(value = "/create/v2")
public ApiResponse<String> createV2(@Valid @RequestBody ProgramOrderCreateDto programOrderCreateDto) {
return ApiResponse.ok(ProgramOrderContext.get(ProgramOrderVersion.V2_VERSION.getVersion())
.createOrder(programOrderCreateDto));
}
// 其他版本接口类似...
}2.3 策略模式中的策略选择判断逻辑
在淘票票项目中,策略模式的策略选择采用了两种主要的判断逻辑实现方式,分别应用于不同的业务场景:
2.3.1 支付策略的选择判断逻辑
支付策略使用了基于Spring容器自动发现和注册的策略选择机制,其核心流程如下:
策略注册:
- 所有支付策略实现类(如AlipayStrategyHandler)都实现了
PayStrategyHandler接口 - 每个策略实现类通过
getChannel()方法返回唯一的渠道标识(如alipay) PayStrategyInitHandler作为Spring初始化处理器,在应用启动时执行策略注册:// 从Spring容器获取所有PayStrategyHandler类型的Bean Map<String, PayStrategyHandler> payStrategyHandlerMap = context.getBeansOfType(PayStrategyHandler.class); // 遍历并注册每个策略,使用策略自身提供的channel作为key for (Entry<String, PayStrategyHandler> entry : payStrategyHandlerMap.entrySet()) { PayStrategyHandler payStrategyHandler = entry.getValue(); payStrategyContext.put(payStrategyHandler.getChannel(), payStrategyHandler); }
- 所有支付策略实现类(如AlipayStrategyHandler)都实现了
策略选择:
- 客户端调用时,传入具体的支付渠道标识(channel参数)
- PayStrategyContext通过channel参数直接从Map中获取对应的策略实现:
// 根据channel参数从Map中查找对应的策略实现 public PayStrategyHandler get(String channel) { return Optional.ofNullable(payStrategyHandlerMap.get(channel)) .orElseThrow(() -> new TaoPiaoPiaoFrameException(BaseCode.PAY_STRATEGY_NOT_EXIST)); } - 如果找不到对应的策略,会抛出明确的异常提示
2.3.2 订单创建策略的选择判断逻辑
订单创建策略使用了基于版本号静态注册的策略选择机制,其核心流程如下:
策略注册:
- 各版本订单策略实现类(如ProgramOrderV1Strategy、ProgramOrderV2Strategy等)在初始化时,通过调用
ProgramOrderContext.add()方法将自身注册到上下文 - 策略实现类继承了
AbstractApplicationCommandLineRunnerHandler,确保在应用启动时完成注册 - 注册时使用版本号作为key,策略实现作为value
- 各版本订单策略实现类(如ProgramOrderV1Strategy、ProgramOrderV2Strategy等)在初始化时,通过调用
策略选择:
- 控制器层通过URI路径区分不同版本的接口(如
/program/order/create/v1、/program/order/create/v2) - 每个接口方法对应一个固定的版本策略,通过
ProgramOrderVersion枚举获取版本标识 - 调用
ProgramOrderContext.get(version)方法,根据版本号从静态Map中获取对应的策略实现:// 在控制器中根据版本枚举获取对应策略 ProgramOrderContext.get(ProgramOrderVersion.V1_VERSION.getVersion()).createOrder(programOrderCreateDto); - 同样,如果找不到对应版本的策略,会抛出异常
- 控制器层通过URI路径区分不同版本的接口(如
2.3.3 策略选择判断逻辑的优势
松耦合设计:
- 策略选择逻辑与具体策略实现完全分离
- 添加新策略时无需修改现有代码,符合开闭原则
高效查找:
- 使用HashMap作为策略存储容器,确保O(1)时间复杂度的策略查找
清晰的异常处理:
- 当策略不存在时,提供明确的异常信息,便于调试和排错
自动化注册:
- 支付策略通过Spring容器自动发现和注册,减少手动配置
- 订单策略通过版本枚举集中管理,便于维护和扩展
2.2.3 锁超时策略
在分布式锁模块中,通过策略模式处理锁获取超时的情况:
LockTimeOutStrategy枚举定义了锁超时处理策略:
public enum LockTimeOutStrategy implements LockTimeOutHandler{
FAIL(){
@Override
public void handler(String lockName) {
String msg = String.format("%s请求频繁",lockName);
throw new RuntimeException(msg);
}
}
}3. 单例模式(Singleton Pattern)
3.1 模式定义
单例模式是一种创建型设计模式,让你能够保证一个类只有一个实例,并提供一个访问该实例的全局节点。
3.2 项目应用
在淘票票项目中,许多Spring管理的Bean实际上就是单例模式的体现,如各种Service、Mapper、Util类等。Spring默认的Bean作用域就是单例。
4. 装饰器模式(Decorator Pattern)
4.1 模式定义
装饰器模式是一种结构型设计模式,允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。
4.2 项目应用
在网关的请求处理中,使用了装饰器模式来包装请求对象:
private ServerHttpRequestDecorator decorateHead(ServerWebExchange exchange, HttpHeaders headers, CachedBodyOutputMessage outputMessage, RequestTemporaryWrapper requestTemporaryWrapper, Map<String,String> headMap){
return new ServerHttpRequestDecorator(exchange.getRequest()){
@Override
public HttpHeaders getHeaders() {
// 装饰原始请求头
}
@Override
public Flux<DataBuffer> getBody() {
// 装饰原始请求体
return outputMessage.getBody();
}
};
}5. 代理模式(Proxy Pattern)
5.1 模式定义
代理模式是一种结构型设计模式,让你能够提供对象的替代品或其占位符。代理控制着对于原对象的访问,并允许在将请求提交给对象前后进行一些处理。
5.2 项目应用
5.2.1 AOP代理
在分布式锁和防重复执行功能中,使用Spring AOP实现动态代理:
ServiceLockAspect通过切面拦截被@ServiceLock注解标记的方法:
@Aspect
public class ServiceLockAspect {
@Around("@annotation(servicelock)")
public Object around(ProceedingJoinPoint joinPoint, ServiceLock servicelock) throws Throwable {
// 在目标方法执行前后添加分布式锁逻辑
}
}6. 模板方法模式(Template Method Pattern)
6.1 模式定义
模板方法模式是一种行为设计模式,它在超类中定义了一个算法的框架,允许子类在不修改结构的情况下重写算法的特定步骤。
6.2 项目应用
在项目初始化模块中,使用模板方法模式定义了应用启动时的初始化流程:
public abstract class AbstractApplicationCommandLineRunnerHandler implements CommandLineRunner, Ordered {
@Override
public final void run(String... args) throws Exception {
// 模板方法,定义了执行流程
executeInit();
}
// 子类需要实现的具体方法
public abstract void executeInit();
}7. 观察者模式(Observer Pattern)
7.1 模式定义
观察者模式是一种行为设计模式,允许你定义一种订阅机制,可在对象事件发生时通知多个"观察"该对象的其他对象。
7.2 项目应用
Spring框架本身大量使用了观察者模式,如事件监听机制。在淘票票项目中,通过@EventListener注解实现事件监听:
@Component
public class DataInitListener {
@EventListener
public void handleDataInitEvent(DataInitEvent event) {
// 处理数据初始化事件
}
}8. 建造者模式(Builder Pattern)
8.1 模式定义
建造者模式是一种创建型设计模式,使你能够分步骤创建复杂对象。该模式允许你使用相同的创建代码生成不同类型和形式的对象。
8.2 项目应用
在灰度发布组件中使用了建造者模式:
public class EnhanceServiceInstanceListSupplierBuilder {
// 通过建造者模式构建服务实例列表
}总结
淘票票项目通过合理运用各种设计模式,构建了一个高内聚、低耦合、易扩展的系统架构。这些设计模式的应用不仅提高了代码的可维护性,也增强了系统的稳定性和可扩展性,为应对高并发场景提供了坚实的基础。