You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AJ Riel启发式规则5.7/3.7关联及面向对象类继承设计疑问

面向对象设计启发式规则问题解答

以下回答基于AJ Riel提出的面向对象设计经验准则展开,所有规则均为设计权衡参考,而非语法层面的强制要求。

1. 为什么除继承树叶子节点外的所有类都应当设置为抽象类?

这条规则的核心是对齐类的语义与真实业务实体的映射关系,避免无意义实例和不可预期的行为,主要有三点原因:

  • 非叶子节点类本质是对一组子类公共属性、行为的抽象,本身不对应业务中的完整实体。比如Employee作为基类抽象了所有员工的姓名、工号等共性,但不存在“没有具体类型的员工”这种真实业务对象,实例化它没有实际业务价值。
  • 避免不完整行为被调用。非叶子类的很多方法通常没有通用实现,需要子类根据自身特性重写,如果设为具体类,实例化后调用未适配当前场景的方法会直接产生逻辑错误。比如通用Employee的calculate_salary()方法没有普适实现,直接调用只会得到错误结果。
  • 强制子类实现统一接口。将非叶子类设为抽象类可以通过抽象方法的语法约束,保证所有子类都必须实现约定的公共接口,不会出现遗漏实现导致的行为不一致问题,也符合里氏替换原则的要求。

2. 启发式规则3.7(从设计中剔除不相关的类)作为该规则的例外的关联逻辑?

两条规则的关联核心是避免为了遵守抽象约束而产生无意义的冗余类,本质是设计优先级的权衡:

  • 规则5.7的适用前提是继承树已经存在,也就是你确实需要对一类实体做不同特化。如果你的业务场景中某个类根本不需要派生任何子类,强行给它套一个抽象父类只为了遵守“基类必须是抽象类”的规则,那这个额外的抽象父类就是和业务无关的冗余类,违反规则3.7的要求,应该直接剔除,把原来的具体类作为叶子节点即可。
  • 另一种场景是,某些基类本身的所有方法都有通用的、不需要子类重写的实现,且业务中确实需要实例化这个基类,就没必要强行拆分出抽象层,否则产生的额外抽象类同样属于无意义的冗余类,不符合规则3.7的要求。
    简单来说:设计永远以业务需要为核心,不能为了遵守规则而生造不需要的类。

3. 允许实例化Employee、Person、Human、LivingBeing这些类的认知是否合理?

这个认知是否合理完全取决于你的业务场景,没有统一答案,可以结合两条启发式规则推导判断:

  1. 先应用规则3.7筛选相关类:如果你的业务是人力资源管理系统,核心只需要处理员工相关逻辑,那LivingBeing、Human这些类完全是和业务无关的冗余类,应该直接从设计中删除,根本谈不到是否允许实例化的问题。
  2. 再应用规则5.7判断剩余类:对剩下的业务相关类,看它是不是继承树的非叶子节点。如果你的业务中Employee确实有全职员工、兼职员工、实习生等多个子类,那Employee属于非叶子节点,不应该允许实例化;如果你的业务非常简单,不需要区分任何员工类型,Employee本身就是继承树的叶子节点,没有任何子类,那允许实例化完全合理。
    如果你的设计中同时存在这四个类且都是业务必须的,越上层的类(比如LivingBeing)抽象程度越高,越不可能对应具体的业务实体,允许实例化的合理性就越低。

内容的提问来源于stack exchange,提问作者Asier Naiz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 09:09:02