面试题答案
一键面试过度重写对代码维护性的影响
- 代码可读性降低:过多重写使得方法的行为在多个子类中分散,难以快速定位和理解特定行为的实现逻辑。例如,在一个图形绘制的类继承体系中,
Shape
类有多个子类如Circle
、Rectangle
等,若每个子类都过度重写draw
方法,当需要查看某种图形绘制逻辑时,需在每个子类中查找,增加阅读成本。 - 维护成本增加:当基类方法的核心逻辑需要修改时,由于过度重写,每个重写该方法的子类都可能需要同步修改,否则可能出现不一致的行为。这增加了维护过程中的工作量和出错风险。例如,基类
Shape
中draw
方法原本使用某种颜色绘制,若要修改为另一种绘制方式,每个子类的draw
方法都要相应调整。 - 破坏设计模式的初衷:在依赖倒置原则等设计原则下,高层模块依赖于抽象而非具体实现。过度重写可能导致子类过于依赖基类的具体实现细节,破坏了这种依赖关系。例如,在策略模式中,若策略类过度重写基类方法,可能使得策略类与上下文类的耦合度增加,违背策略模式的初衷。
解决方案
- 模板方法模式
- 实现方式:在基类中定义一个模板方法,该方法包含算法的骨架,将一些步骤定义为抽象方法,由子类实现。例如,在
Shape
类中定义draw
模板方法,包含通用的绘制前准备、绘制主体和绘制后清理步骤,其中绘制主体步骤定义为抽象方法,由Circle
、Rectangle
等子类实现。 - 优点:
- 提高代码复用性,基类的模板方法中的通用逻辑可被所有子类复用。
- 遵循开闭原则,当需要新增一种图形绘制逻辑时,只需新增一个子类实现抽象方法,无需修改基类代码。
- 缺点:
- 子类过度依赖基类的模板方法结构,若基类模板方法结构改变,可能影响到所有子类。
- 增加了代码的抽象层次,对于初学者理解起来有一定难度。
- 实现方式:在基类中定义一个模板方法,该方法包含算法的骨架,将一些步骤定义为抽象方法,由子类实现。例如,在
- 组合模式
- 实现方式:将需要变化的行为封装成独立的类,然后在基类或子类中通过组合的方式使用这些类。例如,对于
Shape
的draw
行为,可将绘制颜色、绘制线条等行为分别封装成ColorDrawer
、LineDrawer
类,在Shape
或其子类中组合使用这些类来完成绘制。 - 优点:
- 提高代码的灵活性和可维护性,行为类可独立变化和复用,如
ColorDrawer
可被多种图形类使用。 - 降低类之间的耦合度,子类只关注组合的行为类,不依赖基类的具体实现细节。
- 提高代码的灵活性和可维护性,行为类可独立变化和复用,如
- 缺点:
- 可能会增加类的数量,导致项目结构复杂。
- 组合关系的配置和管理相对复杂,若使用不当可能出现错误。
- 实现方式:将需要变化的行为封装成独立的类,然后在基类或子类中通过组合的方式使用这些类。例如,对于
- 依赖注入
- 实现方式:通过构造函数、方法参数等方式将依赖的对象注入到类中。例如,在
Shape
类的构造函数中传入一个实现了DrawingStrategy
接口的对象,Shape
类在draw
方法中调用该对象的方法来完成绘制,子类可根据需求传入不同的实现类。 - 优点:
- 增强了代码的可测试性,可通过传入模拟对象来测试
Shape
类的功能。 - 提高了代码的可维护性和扩展性,当需要改变绘制策略时,只需传入新的实现类,无需修改
Shape
类及其子类的代码。
- 增强了代码的可测试性,可通过传入模拟对象来测试
- 缺点:
- 增加了代码的复杂性,需要管理依赖对象的创建和注入。
- 若依赖关系处理不当,可能导致运行时错误。
- 实现方式:通过构造函数、方法参数等方式将依赖的对象注入到类中。例如,在