跳到主要内容

消息点赞点踩策略模式

我们可以对某个人发送的消息进行点赞和点踩

需要注意的是,一开始我们给一个消息点赞,此时这个人的点赞数量是1

如果这时候,我们选择点踩,那么应该先取消原来的点赞,然后再进行点踩操作,这时候点赞数量就是-1

这个过程如果用大量的ifelse写就不是很优雅

if(点赞){
if(点过了踩){
//取消点踩
}
}else if(点踩){
if(点过了赞){
//取消点赞
}
}

消除if-else最常见的手段就是使用策略模式。

image-20240529213050580

在点赞或者点踩的时候,根据不同的type加载不同的策略

@Override
public void setMsgMark(Long uid, ChatMessageMarkReq request) {
AbstractMsgMarkStrategy strategy = MsgMarkFactory.getStrategyNoNull(request.getMarkType());
switch (MessageMarkActTypeEnum.of(request.getActType())) {
case MARK:
strategy.mark(uid, request.getMsgId());
break;
case UN_MARK:
strategy.unMark(uid, request.getMsgId());
break;
}
}

点赞策略:

点赞的同时,如果之前有点踩,需要取消点踩的动作

@Component
public class LikeStrategy extends AbstractMsgMarkStrategy {

@Override
protected MessageMarkTypeEnum getTypeEnum() {
return MessageMarkTypeEnum.LIKE;
}

@Override
public void doMark(Long uid, Long msgId) {
super.doMark(uid, msgId);
//同时取消点踩的动作
MsgMarkFactory.getStrategyNoNull(MessageMarkTypeEnum.DISLIKE.getType()).unMark(uid, msgId);
}
}

具体的实现:

protected void exec(Long uid, Long msgId, MessageMarkActTypeEnum actTypeEnum) {
Integer markType = getTypeEnum().getType();
Integer actType = actTypeEnum.getType();
MessageMark oldMark = messageMarkService.get(uid, msgId, markType);
if (Objects.isNull(oldMark) && actTypeEnum == MessageMarkActTypeEnum.UN_MARK) {
//取消的类型,数据库一定有记录,没有就直接跳过操作
return;
}
//插入一条新消息,或者修改一条消息
MessageMark insertOrUpdate = MessageMark.builder()
.id(Optional.ofNullable(oldMark).map(MessageMark::getId).orElse(null))
.uid(uid)
.msgId(msgId)
.type(markType)
.status(transformAct(actType))
.build();
boolean modify = messageMarkService.saveOrUpdate(insertOrUpdate);
if (modify) {
//修改成功才发布消息标记事件
ChatMessageMarkDTO dto = new ChatMessageMarkDTO(uid, msgId, markType, actType);
applicationEventPublisher.publishEvent(new MessageMarkEvent(this, dto));
}
}

我们还会有一个监听器,因为如果用户的消息被点赞超过10个 了,我们会给这个用户发放一个勋章

还有一个监听器,就是推送给所有用户

/**
* 消息标记监听器
*/
@Slf4j
@Component
public class MessageMarkListener {
@Async
@TransactionalEventListener(classes = MessageMarkEvent.class, fallbackExecution = true)
public void changeMsgType(MessageMarkEvent event) throws InterruptedException {
ChatMessageMarkDTO dto = event.getDto();
Message msg = messageService.getById(dto.getMsgId());
if (!Objects.equals(msg.getType(), MessageTypeEnum.TEXT.getType())) {// 普通消息才需要升级
return;
}
// 消息被标记次数
Integer markCount = messageMarkService.getMarkCount(dto.getMsgId(), dto.getMarkType());
MessageMarkTypeEnum markTypeEnum = MessageMarkTypeEnum.of(dto.getMarkType());
if (markCount < markTypeEnum.getRiseNum()) {
return;
}
if (MessageMarkTypeEnum.LIKE.getType().equals(dto.getMarkType())) {// 尝试给用户发送一张徽章
userBackpackService.acquireItem(msg.getFromUid(), ItemEnum.LIKE_BADGE.getId(), IdempotentEnum.MSG_ID, msg.getId().toString());
}
}

@Async
@TransactionalEventListener(classes = MessageMarkEvent.class, fallbackExecution = true)
public void notifyAll(MessageMarkEvent event) {// 后续可做合并查询,目前异步影响不大
ChatMessageMarkDTO dto = event.getDto();
Integer markCount = messageMarkService.getMarkCount(dto.getMsgId(), dto.getMarkType());
pushService.sendPushMsg(WSAdapter.buildMsgMarkSend(dto, markCount));
}

}