
本文介绍一种基于依赖注入与模板方法模式的设计方案:将各类校验器(如轮胎、刹车、油量)在对象创建后预先注入子类实例,使抽象父类 `vehicle` 的 `runallvalidations()` 方法可无参数、无 `if` 分支地完成类型专属的完整校验流程。
在面向对象设计中,避免运行时类型判断(如 instanceof 或 if-else 链)的关键在于将“决策权”前移至对象构建阶段,而非执行阶段。本方案摒弃了“向通用方法传入所有可能校验器”的冗余方式,也规避了显式类型检查的坏味道,转而采用 “校验器注入 + 模板方法” 的组合策略,既保持接口统一性,又确保行为专一性。
✅ 核心设计思想
- 职责分离:Vehicle 定义统一入口 runAllValidations(),但不参与具体校验逻辑;各子类负责声明自身所需的校验器字段,并在 runAllValidations() 中按需调用对应 checkXxx() 方法。
- 依赖前置注入:校验器(TireValidator、BrakeValidator、GasValidator)不在调用时传入,而是在对象初始化后通过 setXxxValidator() 显式注入——这使校验逻辑完全解耦于调用上下文。
- 多态驱动执行:main 中只需持有 Vehicle 类型引用,调用 runAllValidations() 即可自动触发子类定制化逻辑,真正实现“一个接口,多种实现”。
? 完整代码示例
// 抽象基类:定义公共校验能力与统一入口
abstract class Vehicle {
protected Tire tire;
protected TireValidator tireValidator;
public void setTireValidator(TireValidator tireValidator) {
this.tireValidator = tireValidator;
}
protected void checkTire() {
if (tireValidator != null) {
tireValidator.check(tire);
} else {
throw new IllegalStateException("TireValidator not set for " + getClass().getSimpleName());
}
}
public abstract void runAllValidations();
}
// 子类 Bike:仅关注轮胎 + 刹车
class Bike extends Vehicle {
private Brakes brakes;
private BrakeValidator brakeValidator;
public void setBrakeValidator(BrakeValidator brakeValidator) {
this.brakeValidator = brakeValidator;
}
protected void checkBrakes() {
if (brakeValidator != null) {
brakeValidator.check(brakes);
} else {
throw new IllegalStateException("BrakeValidator not set for Bike");
}
}
@Override
public void runAllValidations() {
checkTire(); // 复用父类逻辑
checkBrakes(); // 扩展自身逻辑
}
}
// 子类 Car:仅关注轮胎 + 油量
class Car extends Vehicle {
private Gas gas;
private GasValidator gasValidator;
public void setGasValidator(GasValidator gasValidator) {
this.gasValidator = gasValidator;
}
protected void checkGas() {
if (gasValidator != null) {
gasValidator.check(gas);
} else {
throw new IllegalStateException("GasValidator not set for Car");
}
}
@Override
public void runAllValidations() {
checkTire(); // 复用父类逻辑
checkGas(); // 扩展自身逻辑
}
}? 使用方式(零条件、零冗余参数)
public static void main(String[] args) {
// 实例化校验器(假设已实现)
TireValidator tireValidator = new DefaultTireValidator();
BrakeValidator brakeValidator = new DefaultBrakeValidator();
GasValidator gasValidator = new DefaultGasValidator();
// 构建具体车辆并注入其专属校验器
Bike bike = new Bike();
bike.setTireValidator(tireValidator);
bike.setBrakeValidator(brakeValidator);
Car car = new Car();
car.setTireValidator(tireValidator);
car.setGasValidator(gasValidator);
// 统一调用 —— 无需 if,无需传参,无需关心具体类型
List vehicles = List.of(bike, car);
vehicles.forEach(Vehicle::runAllValidations); // ✅ 多态自动分发
// 或单独调用
car.runAllValidations(); // → checkTire() + checkGas()
bike.runAllValidations(); // → checkTire() + checkBrakes()
} ⚠️ 注意事项与最佳实践
- 空校验防护:示例中在 checkXxx() 内添加了 null 检查并抛出明确异常,避免静默失败;生产环境建议结合 Objects.requireNonNull() 或构造器强制注入(如使用 Spring 的 @RequiredArgsConstructor)进一步强化契约。
- 扩展性友好:新增车辆类型(如 Truck 需校验载重与灯光)只需继承 Vehicle、注入对应校验器、重写 runAllValidations(),无需修改任何现有类或条件逻辑。
- 替代进阶方案:若校验器生命周期复杂(如需复用、代理、AOP 增强),可考虑引入 ValidatorRegistry 或依赖注入框架(如 Spring)管理校验器 Bean,再通过 @Autowired 自动装配到子类中,进一步降低手动注入成本。
该方案以简洁、可读、可维护的方式,完美践行了 “开闭原则” 与 “里氏替换原则”,是消除类型判断、提升多态价值的经典实践。









