##将发红包抽象成handler模型

发放红包是高频开发需求,将每个条件校验抽象成 handler 模型,对部分参数进行配置化,使得后面的红包需求开发量越来越少,极大提高代码复用率。使用java实现出来。

你这个想法很棒,是一个典型的规则引擎式设计 ,通过将每个发放红包的业务规则抽象成 Handler(处理器) ,实现一个可配置的、可扩展的链式校验系统。下面是一个用 Java 实现的完整思路和代码框架:


💡 设计思路

✅ 核心思想:

• 每一个"发红包"的校验条件,抽象为一个 RuleHandler。

• 使用"责任链模式"串联多个 Handler。

• 支持配置式启用某些 Handler(通过配置文件、数据库、策略中心等)。


🧱 类图结构(简化)

lua 复制代码
             +------------------+
             |  RuleHandler     | <-- 接口(抽象规则处理器)
             +------------------+
                      ▲
         +------------+-------------+
         |                          |
+-------------------+     +--------------------+
| LoginDaysHandler  |     | UserLevelHandler   | ...(具体实现类)
+-------------------+     +--------------------+

             +----------------------+
             |  RuleHandlerChain    | <-- 构建责任链 & 执行
             +----------------------+

             +----------------------+
             |  RedPacketService    | <-- 对外发放红包接口
             +----------------------+

🧩 1. 抽象 Handler 接口

arduino 复制代码
public interface RuleHandler {
    boolean handle(RedPacketContext context);
    String getName();
}

🧩 2. 示例 Handler:登录天数校验

typescript 复制代码
public class LoginDaysHandler implements RuleHandler {

    @Override
    public boolean handle(RedPacketContext context) {
        return context.getUser().getLoginDays() >= 7;
    }

    @Override
    public String getName() {
        return "LoginDaysHandler";
    }
}

🧩 3. 示例 Handler:用户等级校验

typescript 复制代码
public class UserLevelHandler implements RuleHandler {

    @Override
    public boolean handle(RedPacketContext context) {
        return context.getUser().getLevel() >= 3;
    }

    @Override
    public String getName() {
        return "UserLevelHandler";
    }
}

🧩 4. RuleHandlerChain:可配置执行链

arduino 复制代码
public class RuleHandlerChain {

    private final List<RuleHandler> handlers = new ArrayList<>();

    public RuleHandlerChain(List<RuleHandler> allHandlers, List<String> enabledHandlerNames) {
        for (RuleHandler handler : allHandlers) {
            if (enabledHandlerNames.contains(handler.getName())) {
                handlers.add(handler);
            }
        }
    }

    public boolean execute(RedPacketContext context) {
        for (RuleHandler handler : handlers) {
            if (!handler.handle(context)) {
                return false; // 某一环节失败,阻断发红包
            }
        }
        return true;
    }
}

🧩 5. 上下文类 RedPacketContext

typescript 复制代码
public class RedPacketContext {
    private final User user;
    private final Map<String, Object> params = new HashMap<>();

    public RedPacketContext(User user) {
        this.user = user;
    }

    public User getUser() {
        return user;
    }

    public Object getParam(String key) {
        return params.get(key);
    }

    public void setParam(String key, Object value) {
        params.put(key, value);
    }
}

🧩 6. 用户类(简化)

arduino 复制代码
public class User {
    private int loginDays;
    private int level;

    // constructor + getters/setters
}

🧩 7. 红包发放服务

kotlin 复制代码
public class RedPacketService {

    private final RuleHandlerChain ruleHandlerChain;

    public RedPacketService(RuleHandlerChain ruleHandlerChain) {
        this.ruleHandlerChain = ruleHandlerChain;
    }

    public boolean tryGrantRedPacket(RedPacketContext context) {
        if (ruleHandlerChain.execute(context)) {
            // 发放红包逻辑
            System.out.println("✅ 红包发放成功");
            return true;
        } else {
            System.out.println("❌ 红包发放失败,未通过规则校验");
            return false;
        }
    }
}

🔧 8. 配置方式(可来自配置中心、数据库、JSON)

ini 复制代码
public class App {

    public static void main(String[] args) {
        User user = new User();
        user.setLoginDays(10);
        user.setLevel(4);

        RedPacketContext context = new RedPacketContext(user);

        List<RuleHandler> allHandlers = List.of(
            new LoginDaysHandler(),
            new UserLevelHandler()
        );

        // 可配置的启用项
        List<String> enabledRules = List.of(
            "LoginDaysHandler",
            "UserLevelHandler"
        );

        RuleHandlerChain chain = new RuleHandlerChain(allHandlers, enabledRules);
        RedPacketService service = new RedPacketService(chain);

        service.tryGrantRedPacket(context);
    }
}

✅ 优势总结

☑️ 高复用 每个 handler 独立复用,不同活动组合即可
☑️ 易配置 支持配置开关控制规则链
☑️ 易扩展 新增规则只需添加新 handler
☑️ 易测试 每个 handler 可单测,调试方便

太好了,那我们现在来把这个「规则引擎」模块做得更像一个真正可配置、可插拔的 Spring Boot 模块,让你后续几乎零改动就能支持新的活动规则。

🚀 扩展目标

✅ 使用 Spring Boot 支持:

  1. 使用注解标记 RuleHandler

  2. 自动收集所有 RuleHandler Bean

  3. 通过配置文件控制启用哪些 handler

  4. Spring Boot Starter 风格:可独立打包复用

🧩 第一步:创建注解 @Rule

用于标记每一个 Handler 的唯一名称。

less 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component  // 让 Spring 自动扫描
public @interface Rule {
    String value();  // handler 的唯一标识
}

🧩 第二步:修改接口 RuleHandler

java 复制代码
public interface RuleHandler {
    boolean handle(RedPacketContext context);
}

❗ 不再需要 getName 方法,使用 @Rule("xxx") 代替。

🧩 第三步:示例 handler 使用注解

typescript 复制代码
@Rule("LoginDaysHandler")
public class LoginDaysHandler implements RuleHandler {

    @Override
    public boolean handle(RedPacketContext context) {
        return context.getUser().getLoginDays() >= 7;
    }
}

🧩 第四步:Handler 自动收集器 RuleHandlerFactory

收集所有 handler,并根据配置启用

kotlin 复制代码
@Component
public class RuleHandlerFactory {

    private final Map<String, RuleHandler> ruleHandlerMap = new HashMap<>();

    @Autowired
    public RuleHandlerFactory(List<RuleHandler> handlers) {
        for (RuleHandler handler : handlers) {
            Rule annotation = handler.getClass().getAnnotation(Rule.class);
            if (annotation != null) {
                ruleHandlerMap.put(annotation.value(), handler);
            }
        }
    }

    public List<RuleHandler> getHandlers(List<String> enabledRuleNames) {
        return enabledRuleNames.stream()
                .map(ruleHandlerMap::get)
                .filter(Objects::nonNull)
                .toList();
    }
}

🧩 第五步:配置文件控制规则启用

markdown 复制代码
red-packet:
  enabled-rules:
    - LoginDaysHandler
    - UserLevelHandler

对应配置类:

typescript 复制代码
@Configuration
@ConfigurationProperties(prefix = "red-packet")
public class RedPacketProperties {
    private List<String> enabledRules = new ArrayList<>();

    public List<String> getEnabledRules() {
        return enabledRules;
    }

    public void setEnabledRules(List<String> enabledRules) {
        this.enabledRules = enabledRules;
    }
}

🧩 第六步:注入规则链与服务

kotlin 复制代码
@Service
public class RedPacketService {

    private final RuleHandlerChain ruleHandlerChain;

    @Autowired
    public RedPacketService(RuleHandlerFactory factory, RedPacketProperties properties) {
        List<RuleHandler> handlers = factory.getHandlers(properties.getEnabledRules());
        this.ruleHandlerChain = new RuleHandlerChain(handlers);
    }

    public boolean tryGrantRedPacket(RedPacketContext context) {
        if (ruleHandlerChain.execute(context)) {
            System.out.println("✅ 红包发放成功");
            return true;
        } else {
            System.out.println("❌ 红包发放失败,未通过规则校验");
            return false;
        }
    }
}

✅ 最终效果

你只需要:

  1. 新增一个类,标注 @Rule("XXX")

  2. 在 application.yml 中加一句:

yaml 复制代码
red-packet:
  enabled-rules:
    - XXX

系统就能自动启用这个规则!无需改代码!

🛠️ 想做成独立模块(Starter)?

你可以将:

• @Rule 注解

• RuleHandler, RuleHandlerChain

• RedPacketProperties, RuleHandlerFactory

• 抽象服务接口

封装到一个模块 rule-engine-spring-boot-starter 中,作为一个通用"规则引擎",可用于红包、优惠券、会员推荐等场景。

相关推荐
Sherry0071 小时前
CSS Grid 交互式指南(译)(下)
css·面试
一只毛驴2 小时前
浏览器中的事件冒泡,事件捕获,事件委托
前端·面试
一只叫煤球的猫2 小时前
你真的处理好 null 了吗?——11种常见但容易被忽视的空值处理方式
java·后端·面试
KarrySmile2 小时前
Day04–链表–24. 两两交换链表中的节点,19. 删除链表的倒数第 N 个结点,面试题 02.07. 链表相交,142. 环形链表 II
算法·链表·面试·双指针法·虚拟头结点·环形链表
一只毛驴3 小时前
谈谈浏览器的DOM事件-从0级到2级
前端·面试
在未来等你3 小时前
RabbitMQ面试精讲 Day 5:Virtual Host与权限控制
中间件·面试·消息队列·rabbitmq
天天摸鱼的java工程师4 小时前
🔧 MySQL 索引的设计原则有哪些?【原理 + 业务场景实战】
java·后端·面试
Enddme5 小时前
《面试必问!JavaScript 中this 全方位避坑指南 (含高频题解析)》
前端·javascript·面试
橘子郡1235 小时前
深入解析Android Binder机制:从原理到实践
面试
CLO_se_6 小时前
嵌入式软件面试八股文
linux·面试