Fork me on GitHub

设备指令下发设计模式

策略模式(Strategy Pattern) + 工厂模式(Factory Pattern) + 命令模式(Command Pattern)

1. 策略模式

封装不同设备的指令生成算法

// 策略接口
public interface CommandGenerateStrategy {

    /**
     * 生成特定设备的下发指令字节数组
     * @param cmdType 指令类型(如开关、查询等)
     * @param params  参数
     * @param deviceId 设备ID
     * @return 指令字节数组
     */
    byte[] generate(String cmdType, Map<String, Object> params, String deviceId);
}


// 示例:设备类型A的指令生成策略
@Component("typeACommandStrategy")
public class TypeACommandStrategy implements CommandGenerateStrategy {

    @Override
    public byte[] generate(String cmdType, Map<String, Object> params, String deviceId) {
        // 类型A专属协议组装逻辑,使用 Hutool 处理字节操作
        // 示例:ByteUtil、StrUtil 等
        return new byte[] { /* 类型A协议字节 */ };
    }
}

// 示例:设备类型B的指令生成策略
@Component("typeBCommandStrategy")
public class TypeBCommandStrategy implements CommandGenerateStrategy {
    // 类型B专属逻辑
}

2. 工厂模式

根据设备类型动态获取策略

@Service
public class CommandGenerateFactory {

    // Spring 自动注入所有策略实现,key 为 Bean 名称
    private final Map<String, CommandGenerateStrategy> strategyMap;

    public CommandGenerateFactory(Map<String, CommandGenerateStrategy> strategyMap) {
        this.strategyMap = strategyMap;
    }

    public CommandGenerateStrategy getStrategy(String deviceType) {
        // 使用 Hutool 优化字符串处理
        String beanName = StrUtil.lowerFirst(deviceType) + "CommandStrategy";
        CommandGenerateStrategy strategy = strategyMap.get(beanName);
        if (strategy == null) {
            throw new UnsupportedOperationException("不支持的设备类型: " + deviceType);
        }
        return strategy;
    }
}

3. 命令模式

将一次下发封装为命令对象,支持高级特性

// 命令接口
public interface DeviceCommand {
    void execute();           // 执行下发
    void undo();              // 可选:撤销指令
    String getCommandId();    // 获取指令唯一ID,用于追踪
}

public class SendDeviceCommand implements DeviceCommand {

    private final String commandId = IdUtil.simpleUUID(); // Hutool 生成简洁UUID
    private final String deviceType;
    private final String cmdType;
    private final Map<String, Object> params;
    private final String deviceId;
    private final CommandGenerateFactory factory;
    private final CommunicationService commService; // 通信服务(如MQTT、Netty等)

    private byte[] generatedBytes; // 缓存生成的指令

    public SendDeviceCommand(String deviceType, String cmdType,
                             Map<String, Object> params, String deviceId,
                             CommandGenerateFactory factory, CommunicationService commService) {
        this.deviceType = deviceType;
        this.cmdType = cmdType;
        this.params = params;
        this.deviceId = deviceId;
        this.factory = factory;
        this.commService = commService;
    }

    @Override
    public void execute() {
        // 1. 使用工厂 + 策略生成指令
        //使用工厂方法,根据设备类型获取对应的指令策略类
        CommandGenerateStrategy strategy = factory.getStrategy(deviceType);
        //调用策略的生成指令类
        generatedBytes = strategy.generate(cmdType, params, deviceId);

        // 2. 通过通信层实际下发
        commService.send(deviceId, generatedBytes);

        // 3. 记录日志(可落库)
        log.info("指令下发成功 commandId={} deviceId={} cmdType={}", commandId, deviceId, cmdType);
    }

    @Override
    public void undo() {
        // 可选实现:发送反向指令
    }

    @Override
    public String getCommandId() {
        return commandId;
    }
}

4. Service 层统一调用

@Service
public class DeviceCommandService {

    @Autowired
    private CommandGenerateFactory factory;

    @Autowired
    private CommunicationService commService;

    // 同步立即下发(简单场景)
    public void sendImmediately(String deviceType, String cmdType,
                                Map<String, Object> params, String deviceId) {
        DeviceCommand command = new SendDeviceCommand(deviceType, cmdType, params, deviceId, factory, commService);
        command.execute();
    }

    // 异步队列下发(生产推荐)
    public void sendAsync(String deviceType, String cmdType,
                          Map<String, Object> params, String deviceId) {
        DeviceCommand command = new SendDeviceCommand(deviceType, cmdType, params, deviceId, factory, commService);
        // 放入消息队列(如 RocketMQ、RabbitMQ)或线程池
        commandQueue.offer(command); // 或 asyncExecutor.execute(command::execute);
    }
}
posted @ 2025-12-31 21:26  秋夜雨巷  阅读(21)  评论(0)    收藏  举报