如何在不使用 if 条件的前提下,通过父类单个方法调用实现子类差异化验证逻辑

发布时间 - 2026-01-02 00:00:00    点击率:

本文介绍一种基于**依赖注入 + 模板方法模式**的优雅设计:将具体验证器(如 tirevalidator、brakevalidator)在创建子类实例时预先注入,使 `runallvalidations()` 成为无参、无分支、类型安全的纯多态调用。

在面向对象设计中,当需要对不同子类执行“共性+个性”混合操作(如统一校验轮胎,再分别校验刹车或油量),又希望避免 instanceof 或参数冗余等反模式时,关键在于将“行为差异”转化为“状态差异”——即把验证器作为对象的内部状态(成员变量)而非方法参数,从而让多态方法自然解耦。

以下是一个完整、可运行的设计方案:

✅ 核心设计原则

  • 职责分离:Vehicle 定义通用骨架与公共能力(如 checkTire()),不感知具体验证器类型;
  • 延迟绑定:验证器通过 setter 注入(或构造器注入),确保每个子类只持有其真正需要的验证器;
  • 零条件调度:runAllValidations() 在子类中直接组合已注入的验证逻辑,无需任何 if 或类型判断。

? 代码实现

// 抽象基类:定义公共状态与能力
abstract class Vehicle {
    protected Tire tire;
    protected TireValidator tireValidator;

    public void setTireValidator(TireValidator validator) {
        this.tireValidator = validator;
    }

    protected void checkTire() {
        if (tireValidator == null) {
            throw new IllegalStateException("TireValidator not set");
        }
        tireValidator.check(tire);
    }

    public abstract void runAllValidations();
}

// 子类 Bike:仅需 TireValidator + BrakeValidator
class Bike extends Vehicle {
    private Brakes brakes;
    private BrakeValidator brakeValidator;

    public void setBrakeValidator(BrakeValidator validator) {
        this.brakeValidator = validator;
    }

    protected void checkBrakes() {
        if (brakeValidator == null) {
            throw new IllegalStateException("BrakeValidator not set");
        }
        brakeValidator.check(brakes);
    }

    @Override
    public void runAllValidations() {
        checkTire();   // 公共逻辑
        checkBrakes(); // 特有逻辑
    }
}

// 子类 Car:仅需 TireValidator + GasValidator
class Car extends Vehicle {
    private Gas gas;
    private GasValidator gasValidator;

    public void setGasValidator(GasValidator validator) {
        this.gasValidator = validator;
    }

    protected void checkGas() {
        if (gasValidator == null) {
            throw new IllegalStateException("GasValidator not set");
        }
        gasValidator.check(gas);
    }

    @Override
    public void runAllValidations() {
        checkTire(); // 公共逻辑
        checkGas();  // 特有逻辑
    }
}

▶️ 使用示例(主程序)

public class ValidationDemo {
    public static void main(String[] args) {
        // 创建验证器实例
        TireValidator tireValidator = new TireValidator();
        BrakeValidator brakeValidator = new BrakeValidator();
        GasValidator gasValidator = new GasValidator();

        // 构造具体车辆并注入其所需验证器
        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); // 输出:Tire OK → Brakes OK;Tire OK → Gas OK

        // 也可单独调用
        car.runAllValidations();
        bike.runAllValidations();
    }
}

⚠️ 注意事项与进阶建议

  • 空安全:示例中加入了 null 检查,生产环境推荐配合 Objects.requireNonNull() 或使用 Optional 封装验证器;
  • 构造器注入更优:若验证器是必需依赖(即对象创建后必须可用),应优先使用构造器注入替代 setter,提升不可变性与初始化安全性;
  • 扩展性保障:新增子类(如 Truck 需校验 Cargo 和 Axle)只需继承 Vehicle、添加对应字段/校验方法、重写 runAllValidations(),完全不影响现有代码;
  • 避免“胖接口”陷阱:不采用“传入所有验证器”的方式,从根本上消除参数污染和调用方认知负担。

该方案以简洁的面向对象实践,实现了开闭原则(对扩展开放、对修改关闭)与里氏替换原则(子类可安全替换父类)的双重落地——正是多态价值的典型体现。


# go  # ai  # NULL  # if  # 面向对象  # 封装  # 多态  # 成员变量  # 父类  # 子类  # 继承  # 接口  # 对象  # 仅需  # 是一个  # 进阶  # 主程序  # 只需  # 所需  # 也可 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 企业在线网站设计制作流程,想建设一个属于自己的企业网站,该如何去做?  如何续费美橙建站之星域名及服务?  Laravel怎么实现前端Toast弹窗提示_Laravel Session闪存数据Flash传递给前端【方法】  Laravel如何正确地在控制器和模型之间分配逻辑_Laravel代码职责分离与架构建议  历史网站制作软件,华为如何找回被删除的网站?  Laravel如何使用缓存系统提升性能_Laravel缓存驱动和应用优化方案  Laravel Telescope怎么调试_使用Laravel Telescope进行应用监控与调试  免费的流程图制作网站有哪些,2025年教师初级职称申报网上流程?  HTML5空格在Angular项目里怎么处理_Angular中空格的渲染问题【详解】  Laravel请求验证怎么写_Laravel Validator自定义表单验证规则教程  实例解析Array和String方法  laravel怎么在请求结束后执行任务(Terminable Middleware)_laravel Terminable Middleware请求结束任务执行方法  iOS发送验证码倒计时应用  Laravel如何实现RSS订阅源功能_Laravel动态生成网站XML格式订阅内容【教程】  深圳网站制作的公司有哪些,dido官方网站?  Android仿QQ列表左滑删除操作  php 三元运算符实例详细介绍  Laravel API资源(Resource)怎么用_格式化Laravel API响应的最佳实践  Laravel如何清理系统缓存命令_Laravel清除路由配置及视图缓存的方法【总结】  ,交易猫的商品怎么发布到网站上去?  PythonWeb开发入门教程_Flask快速构建Web应用  如何快速生成高效建站系统源代码?  Android Socket接口实现即时通讯实例代码  ChatGPT回答中断怎么办 引导AI继续输出完整内容的方法  哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?  Laravel的.env文件有什么用_Laravel环境变量配置与管理详解  如何生成腾讯云建站专用兑换码?  夸克浏览器网页跳转延迟怎么办 夸克浏览器跳转优化  Laravel定时任务怎么设置_Laravel Crontab调度器配置  在线制作视频的网站有哪些,电脑如何制作视频短片?  HTML透明颜色代码在Angular里怎么设置_Angular透明颜色使用指南【详解】  如何在橙子建站中快速调整背景颜色?  Laravel怎么实现验证码功能_Laravel集成验证码库防止机器人注册  如何用美橙互联一键搭建多站合一网站?  百度浏览器网页无法复制文字怎么办 百度浏览器复制修复  开心动漫网站制作软件下载,十分开心动画为何停播?  Laravel如何实现邮箱地址验证功能_Laravel邮件验证流程与配置  Android利用动画实现背景逐渐变暗  如何正确下载安装西数主机建站助手?  Laravel如何创建自定义Artisan命令?(代码示例)  香港服务器网站生成指南:免费资源整合与高速稳定配置方案  Laravel怎么实现微信登录_Laravel Socialite第三方登录集成  Laravel如何创建自定义中间件?(Middleware代码示例)  使用豆包 AI 辅助进行简单网页 HTML 结构设计  如何在建站之星网店版论坛获取技术支持?  如何在腾讯云服务器上快速搭建个人网站?  胶州企业网站制作公司,青岛石头网络科技有限公司怎么样?  公司网站制作价格怎么算,公司办个官网需要多少钱?  如何快速搭建二级域名独立网站?  香港服务器建站指南:免备案优势与SEO优化技巧全解析