1098 字
5 分钟
模板方法模式
介绍
对原理类图的说明:
AbstractClass 抽象类, 类中实现了模板方法(template),定义了算法的骨架,具体子类需要去实现 其它的抽象方法
ConcreteClass 具体类, 实现了抽象类中的抽象方法
也就是父类模板方法定义不变的流程,子类重写流程中的方法。
①、AbstractClass 抽象模板
一、基本方法
上面的 baseOperation() 或者 customOperation() 方法,也叫基本操作,是由子类实现的方法,并且在模板方法中被调用。
基本方法尽量设计为protected类型, 符合迪米特法则, 不需要暴露的属性或方法尽量不要设置为protected类型。 实现类若非必要, 尽量不要扩大父类中的访权限。
二、模板方法
上面的 templateMethod() 方法,可以有一个或者几个,实现对基本方法的调度,完成固定的逻辑。
为了防止恶意操作,通常模板方法都加上 final 关键字,不允许覆写。
②、ConcreteClass 具体模板
实现父类定义的一个或多个抽象方法,也就是父类定义的基本方法在子类中得以实现。
应用
这个设计模式我们可以拿来做mq的发送和封装
我们在抽象模板中实现通用的sendMessage方法
,在具体模板中实现具体的消息构建和封装发送逻辑。
定义消息发送事件基础扩充属性实体
@Data@NoArgsConstructor@AllArgsConstructor@Builderpublic final class BaseSendExtendDTO {
/** * 事件名称 */ private String eventName;
/** * 主题 */ private String topic;
/** * 标签 */ private String tag;
/** * 业务标识 */ private String keys;
/** * 发送消息超时时间 */ private Long sentTimeout;
/** * 具体延迟时间 */ private Long delayTime;}
我们这样定义抽象模板: AbstractCommonSendProduceTemplate
抽象模板
/** * RocketMQ 抽象公共发送消息组件 */@RequiredArgsConstructor@Slf4j(topic = "CommonSendProduceTemplate")public abstract class AbstractCommonSendProduceTemplate<T> {
private final RocketMQTemplate rocketMQTemplate;
/** * 构建消息发送事件基础扩充属性实体 * * @param messageSendEvent 消息发送事件 * @return 扩充属性实体 */ protected abstract BaseSendExtendDTO buildBaseSendExtendParam(T messageSendEvent);
/** * 构建消息基本参数,请求头、Keys... * * @param messageSendEvent 消息发送事件 * @param requestParam 扩充属性实体 * @return 消息基本参数 */ protected abstract Message<?> buildMessage(T messageSendEvent, BaseSendExtendDTO requestParam);
/** * 消息事件通用发送 * * @param messageSendEvent 消息发送事件 * @return 消息发送返回结果 */ public SendResult sendMessage(T messageSendEvent) { BaseSendExtendDTO baseSendExtendDTO = buildBaseSendExtendParam(messageSendEvent); SendResult sendResult; try { // 构建 Topic 目标落点 formats: `topicName:tags` StringBuilder destinationBuilder = StrUtil.builder().append(baseSendExtendDTO.getTopic()); if (StrUtil.isNotBlank(baseSendExtendDTO.getTag())) { destinationBuilder.append(":").append(baseSendExtendDTO.getTag()); }
// 延迟时间不为空,发送任意延迟消息,否则发送普通消息 if (baseSendExtendDTO.getDelayTime() != null) { sendResult = rocketMQTemplate.syncSendDeliverTimeMills( destinationBuilder.toString(), buildMessage(messageSendEvent, baseSendExtendDTO), baseSendExtendDTO.getDelayTime() ); } else { sendResult = rocketMQTemplate.syncSend( destinationBuilder.toString(), buildMessage(messageSendEvent, baseSendExtendDTO), baseSendExtendDTO.getSentTimeout() ); }
log.info("[生产者] {} - 发送结果:{},消息ID:{},消息Keys:{}", baseSendExtendDTO.getEventName(), sendResult.getSendStatus(), sendResult.getMsgId(), baseSendExtendDTO.getKeys()); } catch (Throwable ex) { log.error("[生产者] {} - 消息发送失败,消息体:{}", baseSendExtendDTO.getEventName(), JSON.toJSONString(messageSendEvent), ex); throw ex; }
return sendResult; }}
具体模板
这里举个例子,我们做一个短信通知的,定义MessageNotifyEvent
@Slf4j@Componentpublic class SmsNotificationProducer extends AbstractCommonSendProduceTemplate<MessageNotifyEvent> {
private final ConfigurableEnvironment environment;
public SmsNotificationProducer(@Autowired RocketMQTemplate rocketMQTemplate, @Autowired ConfigurableEnvironment environment) { super(rocketMQTemplate); this.environment = environment; }
@Override protected BaseSendExtendDTO buildBaseSendExtendParam(MessageNotifyEvent messageSendEvent) { return BaseSendExtendDTO.builder() .eventName("短信通知发送") .keys(String.valueOf(messageSendEvent.getNotificationId())) .topic(environment.resolvePlaceholders(MerchantAdminRocketMQConstant.SMS_NOTIFICATION_TOPIC_KEY)) .sentTimeout(3000L) .build(); }
@Override protected Message<?> buildMessage(MessageNotifyEvent messageSendEvent, BaseSendExtendDTO requestParam) { String keys = StrUtil.isEmpty(requestParam.getKeys()) ? UUID.randomUUID().toString() : requestParam.getKeys(); return MessageBuilder .withPayload(new MessageWrapper(keys, messageSendEvent)) .setHeader(MessageConst.PROPERTY_KEYS, keys) .setHeader(MessageConst.PROPERTY_TAGS, requestParam.getTag()) .build(); }}
补充说明
为了使上述示例能够完整运行,还需要定义以下类:
MessageNotifyEvent
- 短信通知事件类:
@Data@NoArgsConstructor@AllArgsConstructor@Builderpublic class MessageNotifyEvent { private Long notificationId; private String phoneNumber; private String messageContent; private String sender;}
MessageWrapper
- 消息包装类:
@Data@NoArgsConstructor@AllArgsConstructorpublic class MessageWrapper { private String key; private Object payload;
public MessageWrapper(String key, Object payload) { this.key = key; this.payload = payload; }}
SmsNotificationConsumer
- 短信通知消费者类:
@Slf4j@Component@RocketMQMessageListener( topic = MerchantAdminRocketMQConstant.SMS_NOTIFICATION_TOPIC_KEY, consumerGroup = MerchantAdminRocketMQConstant.SMS_NOTIFICATION_CONSUMER_GROUP)public class SmsNotificationConsumer implements RocketMQListener<MessageWrapper> {
@Override public void onMessage(MessageWrapper messageWrapper) { MessageNotifyEvent event = (MessageNotifyEvent) messageWrapper.getPayload(); log.info("[短信消费者] 收到短信通知消息 - ID: {}, 手机号: {}, 内容: {}, 发送者: {}", event.getNotificationId(), event.getPhoneNumber(), event.getMessageContent(), event.getSender());
// 模拟发送短信 System.out.println("[短信服务] 向 " + event.getPhoneNumber() + " 发送短信: " + event.getMessageContent()); }}
通过以上完整的代码示例,我们可以看到模板方法模式在MQ消息发送场景中的应用:
AbstractCommonSendProduceTemplate
定义了消息发送的通用流程(模板方法)SmsNotificationProducer
实现了具体的业务逻辑(构建参数和消息)SmsNotificationConsumer
监听消息并处理- 这样既保证了消息发送流程的一致性,又允许不同业务场景自定义具体实现