在我们对接第三方系统中,我们一般都需要提供一个回调通知地址给第三方,第三方会通过该地址把我们所关心的信息回调通知到我们自己系统中。并且每个回调通知信息都是有标识来区分,如通过字段method(字段名称)。然而我们系统中应该如何去区分处理不同类型的事件呢?很显然不能傻瓜式的通过if else 来实现,这样会使得代码臃肿,难以维护。
下面我们通过策略模式+工厂模式混合模式 解决对接海康平台信息回调处理问题。
策略类&基础类
/**
* 方法枚举
*
* @author LGC
*/
@AllArgsConstructor
@Getter
public enum HikApiMethodEnum {
consume("consume", "核销消费"),
leave("leave", "开闸"),
;
private final String key;
private final String value;
public static HikApiMethodEnum getEnumByKey(String key) {
for (HikApiMethodEnum value : HikApiMethodEnum.values()) {
if (value.getKey().equals(key)) {
return value;
}
}
return null;
}
}
/**
* @author LGC
*/
@Data
public class HikApiRequestPacket implements Serializable {
private static final long serialVersionUID = -5200562843779595856L;
/**
* 方法名
*/
private String method;
/**
* 参数信息 不同method对应不同参数 json
*/
private String params;
}
/**
* 处理海康事件信息 策略接口
*
* @author LGC
*/
public interface IHikApiConsumerService {
/**
* 获取api方法枚举
*
* @return api方法枚举
*/
HikApiMethodEnum getApiMethodEnum();
/**
* 处理事件
*
* @param params 参数
*/
void handle(String params);
}
/**
* 处理海康事件信息--核销 具体策略实现
*
* @author LGC
*/
@Service
@Slf4j
public class ConsumeApiConsumerService implements IHikApiConsumerService {
@Override
public HikApiMethodEnum getApiMethodEnum() {
return HikApiMethodEnum.consume;
}
@Override
public void handle(String params) {
log.info("核销处理:{}", params);
}
}
/**
* 处理海康事件信息--开闸 具体策略实现
*
* @author LGC
*/
@Service
@Slf4j
public class LevelApiConsumerService implements IHikApiConsumerService {
@Override
public HikApiMethodEnum getApiMethodEnum() {
return HikApiMethodEnum.leave;
}
@Override
public void handle(String params) {
log.info("开闸处理:{}", params);
}
}
工厂获取策略类
/**
* 工厂获取策略类
* @author LGC
*/
@Component
public class ApiConsumerFactory {
@Autowired
private List<IHikApiConsumerService> hikApiConsumerServiceList;
public IHikApiConsumerService getHikApiConsumerService(HikApiMethodEnum hikApiMethodEnum) {
Optional<IHikApiConsumerService> first = hikApiConsumerServiceList.stream()
.filter(item -> item.getApiMethodEnum().equals(hikApiMethodEnum)).findFirst();
return first.orElseThrow(() -> new IllegalArgumentException("暂未接入"));
}
}
策略上下文
/**
* 策略上下文
*
* @author LGC
*/
@Slf4j
@Component
public class HikApiContext {
@Autowired
private ApiConsumerFactory apiConsumerFactory;
public void handler(String param) {
HikApiRequestPacket requestPacket = JSONUtil.toBean(param, HikApiRequestPacket.class);
String method = requestPacket.getMethod();
apiConsumerFactory.getHikApiConsumerService(HikApiMethodEnum.getEnumByKey(method)).handle(requestPacket.getParams());
}
}
接收回调通知
@Slf4j
@RestController
public class HikApiController {
@Resource
private HikApiContext hikApiContext;
@PostMapping("/api/hik/gateway")
public String gateway(@RequestBody String param) {
// 处理通知信息
hikApiContext.handler(param);
return "success";
}
}
总结
通过策略模式,我们可以实现不同的事件处理策略,使得系统具有灵活的扩展性和可维护性;而工厂模式则为创建具体策略对象提供了统一的接口,使得客户端代码与具体实现解耦,提高了代码的可读性和可维护性。这种混合使用模式可以帮助我们更好地应对复杂的业务需求,提高软件系统的可扩展性和可维护性。