0

0

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

碧海醫心

碧海醫心

发布时间:2026-01-02 16:41:11

|

428人浏览过

|

来源于php中文网

原创

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

本文介绍一种基于**依赖注入 + 模板方法模式**的优雅设计:将具体验证器(如 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(),完全不影响现有代码;
  • 避免“胖接口”陷阱:不采用“传入所有验证器”的方式,从根本上消除参数污染和调用方认知负担。

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

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

229

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

434

2024.03.01

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

713

2023.08.22

go语言 面向对象
go语言 面向对象

本专题整合了go语言面向对象相关内容,阅读专题下面的文章了解更多详细内容。

54

2025.09.05

java面向对象
java面向对象

本专题整合了java面向对象相关内容,阅读专题下面的文章了解更多详细内容。

47

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

15

2025.11.27

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

994

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

53

2025.10.17

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

145

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 3.2万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号