第4章 面向对象与设计模式面试题:类、继承、多态、单例、工厂、观察者

本章聚焦 Python 面试中高频考察的 面向对象三大特性(封装、继承、多态)以及 经典设计模式(单例、工厂、观察者)。面试官常通过这些问题判断候选人的抽象能力、代码复用意识与系统设计思维。理解核心概念并掌握结构化回答框架,是拿到高分的的关键。

OOP+设计模式回答框架 类与继承 super / MRO / 方法重写 多态 鸭子类型 / 接口统一 单例模式 __new__ / 装饰器 / 模块 工厂模式 简单工厂 / 工厂方法 观察者模式 回调 / 事件 / 解耦

面试问答卡片

📌 面试问题:请解释 Python 中的继承和多态,并举例说明。

面试官考察点:是否理解继承的机制(MRO、super)、方法重写、多态的动态分发以及 Python 特有的鸭子类型。

回答框架:① 先定义继承与多态的概念 → ② 说明 Python 的多继承与 C3 线性化 → ③ 举例展示父类方法和子类重写 → ④ 解释多态如何通过同一接口调用不同实现(鸭子类型)→ ⑤ 总结应用场景(如框架基类)。

简短示例回答:“继承允许子类复用父类属性和方法,Python 通过 MRO 解决多继承冲突。多态意味着不同对象可以响应相同方法,Python 的鸭子类型使得只要对象有该方法即可调用。例如:Animal 父类定义 speak(),Dog 和 Cat 重写,循环中统一调用 speak()。” (98字)

可能追问:super() 的调用顺序?MRO 如何计算?钻石继承会出现哪些问题?

避坑提醒:不要只背诵理论,必须用实际代码演示。避免提及“调用父类构造”时忽略 super() 的 mro 链式调用细节。

📌 面试问题:请实现一个线程安全的单例模式。

面试官考察点:是否掌握多线程下的竞态条件、锁的使用,以及 Python 中实现单例的多种方式(__new__、装饰器、模块导入)。

回答框架:① 说明单例模式意图:确保一个类只有一个实例 → ② 对比三种实现方式(模块天然单例、__new__ + 锁、装饰器 + 锁)→ ③ 重点给出线程安全的 __new__ 实现(加 threading.Lock)→ ④ 验证双重检查锁定(DCL)可提高性能。

简短示例回答:“使用 __new__ 加锁:_instance = None; _lock = threading.Lock(),在 __new__ 中先检查 _instance is None,若为真则加锁再次检查并创建实例,返回 _instance。模块导入方式则由 Python 解释器保证线程安全。” (99字)

可能追问:为什么需要双重检查?用 classmethod 或 metaclass 实现有何区别?

避坑提醒:不要只给出不加锁的 __new__ 实现;也不要用 @synchronized 这种 Java 思维,要强调 Python 的 threading.Lock。

📌 面试问题:请描述工厂模式在什么场景下使用,并给出一个简单实现。

面试官考察点:是否理解工厂模式解耦对象创建与使用的好处,能否区分简单工厂、工厂方法、抽象工厂。

回答框架:① 指出工厂模式适用于“创建对象逻辑复杂或需要根据条件动态选择类”的场景 → ② 对比直接 new 的弊端 → ③ 给出简单工厂的类图/代码 → ④ 延伸至工厂方法(将创建延迟到子类)→ ⑤ 总结:提高了代码扩展性和维护性。

简短示例回答:“假设有一个日志系统,需要根据配置创建 FileLogger 或 DatabaseLogger。简单工厂:定义一个 LoggerFactory.create(type) 方法,内部用 if-elif 返回相应实例。客户端只需调用工厂,无需知道具体类名,符合开闭原则。” (96字)

可能追问:简单工厂是否违反开闭原则?如何用工厂方法改进?抽象工厂与工厂方法的区别?

避坑提醒:回答时不要只贴代码而不谈场景;避免把工厂模式与构建者模式混淆,强调“创建过程”的封装。

项目案例:电商订单通知系统(观察者模式实战)

项目名称OrderNotify - 订单状态事件驱动系统
业务背景电商平台订单从“创建→支付→发货→完成”需同步通知库存、物流、短信/邮件等多个子系统,使用观察者模式实现松耦合。
规模指标日均订单50万+,订阅者10+个(库存服务、物流接口、推送服务、用户通知等),事件峰值QPS 2000+。
技术栈Python 3.9 + Flask + Redis Pub/Sub + Celery(异步通知) + threading(本地观察者池)
核心难点① 观察者注册/注销的线程安全 ② 事件投递失败的重试与幂等 ③ 避免观察者之间相互阻塞(异步化) ④ 支持动态添加新观察者无需修改核心逻辑。
面试高频追问观察者模式与发布-订阅模式的区别?项目中为什么没有直接用消息队列而自己实现?如何处理观察者异常不阻塞其他观察者?如果通知顺序有要求如何保证?
可迁移回答话术“我在项目中采用观察者模式将订单状态变更作为事件,各子系统作为观察者订阅。主要用 Redis Pub/Sub 实现跨进程通知,本地则用线程池异步分发。这样新增通知渠道时只需添加观察者类并注册,符合开闭原则。同时通过异常隔离和重试队列保证可靠性。” (99字)
观察者模式追问路径 与发布订阅区别? 耦合度、中间件 线程安全如何保证? 锁、队列、异步 异常隔离与重试? try-except 每个观察者 主题与事件溯源 幂等性与补偿

本章核心记忆口诀:“继承多态看 MRO,单例加锁防竞争;工厂解耦创建事,观察者里存回调。” 面试时先亮框架,再带代码,最后讲场景,稳稳拿捏 OOP 与设计模式。