InstanceManager:继承与组合的技术选型探讨
选择继承还是组合使用InstanceManager?
我已实现如下InstanceManager类,用于管理所有创建的实例,并支持通过指定查找键快速查找和检索特定值:
from typing import Callable, Iterable, Hashable, Optional as Opt import threading class InstanceManager[InstanceT, LookupT: Hashable](): def __init__( self, get_lookups: Callable[[InstanceT], Iterable[LookupT]], on_add: Opt[Callable[[InstanceT], None]] = None, on_remove: Opt[Callable[[InstanceT], None]] = None ) -> None: self._on_add = on_add self._on_remove = on_remove self._get_lookups = get_lookups self._all: list[InstanceT] = [] self._lookup: dict[LookupT, InstanceT] = {} self._LOCK = threading.RLock() def lookup(self, lookup: LookupT) -> InstanceT: return self._lookup[lookup] # atomic operation def all_instances(self) -> list[InstanceT]: with self._LOCK: return list(self._all) def get_lookups(self, instance: InstanceT) -> tuple[LookupT, ...]: with self._LOCK: return tuple(k for k, v in self._lookup.items() if v == instance) def add(self, instance: InstanceT) -> None: with self._LOCK: lookup_values = self._get_lookups(instance) if instance in self._all: raise ValueError("Instance already in added") self._all.append(instance) for lv in lookup_values: if lv in self._lookup: raise ValueError("lookup value already used for different instance") self._lookup[lv] = instance if self._on_add is not None: self._on_add(instance) # 修正原代码漏传参问题 def remove(self, instance: InstanceT): with self._LOCK: # 修正原代码遍历字典时pop报错问题:遍历键的副本 for k in list(self._lookup.keys()): if self._lookup[k] == instance: self._lookup.pop(k) self._all.remove(instance) if self._on_remove is not None: self._on_remove(instance) # 修正原代码漏传参问题
现咨询:使用该功能的类应选择继承InstanceManager,还是将其作为类字段采用组合方式?我虽知晓继承是‘is a’关系、组合是‘has a’关系,但仍无法据此做出判断;且多数目标类需继承其他类,采用继承会引发多重继承问题,希望得到专业建议。
专业建议:优先选择组合方式
1. 规避多重继承的复杂度
多数目标类已有自身的父类,Python的多重继承虽然语法支持,但会带来菱形继承、方法解析顺序(MRO)冲突等问题,大幅提升代码的维护难度。组合方式完全避开这些陷阱,目标类只需维护一个InstanceManager类型的字段,逻辑更清晰。
2. 符合语义逻辑
从业务语义看,你的目标类不是一个InstanceManager,而是拥有实例管理的能力。比如一个OrderService,它需要管理订单实例,但OrderService的核心职责是处理订单业务,而非单纯做实例管理,这完全符合"has a"的组合语义,而非"is a"的继承语义。
3. 灵活性更强
- 组合方式允许你随时替换实例管理的实现(比如后续扩展出
PersistentInstanceManager),无需修改目标类的继承结构。 - 可以在目标类中封装
InstanceManager的方法,对外暴露符合业务场景的接口,避免暴露冗余的底层方法。比如目标类可以提供get_order_by_id,而非直接暴露InstanceManager的lookup方法,更贴合单一职责原则。
4. 继承仅适用于极特殊场景
只有当你的目标类本身就是InstanceManager的特化扩展时,比如OrderInstanceManager(专门管理订单实例的管理器),继承才有意义。但根据你的描述,目标类是需要使用实例管理功能的业务类,而非管理器本身,因此继承并不适用。
组合实现示例
class Order: def __init__(self, order_id: str, amount: float): self.order_id = order_id self.amount = amount class OrderService: def __init__(self): # 组合InstanceManager,指定查找键为order_id self._instance_manager = InstanceManager[Order, str]( get_lookups=lambda order: [order.order_id], on_add=lambda order: print(f"订单 {order.order_id} 已添加"), on_remove=lambda order: print(f"订单 {order.order_id} 已移除") ) def create_order(self, order: Order): self._instance_manager.add(order) def get_order(self, order_id: str) -> Order: return self._instance_manager.lookup(order_id) def get_all_orders(self) -> list[Order]: return self._instance_manager.all_instances() def cancel_order(self, order: Order): self._instance_manager.remove(order)
内容的提问来源于stack exchange,提问作者JoniKauf
相关产品推荐
相关产品推荐

