Bob Belderbos:协议还是 ABC?设计可插拔的提供者接口”
作者正在为一款与两个不同图像生成后端交互的 CLI 工具设计共享契约。目标是让 CLI 能够使用通用的 submit(request) 函数,而由每个后端将其转换为自身的 SDK 调用。最初,作者曾考虑使用抽象基类(ABC)作为共享接口,因为它们能够强制实现抽象方法。然而,ABC 需要继承关系,这为第三方可插拔后端引入了耦合。Protocol 类型协议(typing.Protocol)则更为合适,因为它采用结构类型(structural typing)。一个类只要拥有正确签名的相应方法,即可满足 Protocol,而无需显式继承。这种方法将外部实现者与核心包解耦,使提供者能够独立演进。Protocol 促进了基于组合的设计,其中提供者作为值被传递,而非处于严格的继承层次结构中。虽然 Protocol 非常适合描述插件边界,但当提供者需要共享具体行为或实现逻辑时,ABC 更为适用。ABC 可以定义共享方法,并强制具体子类实现这些抽象方法。同时,也可以将两者结合使用:使用 Protocol 定义公共插件边界,使用内部 ABC 在提供者之间共享行为。作者建议默认使用 Protocol,因其契约更轻量,仅在需要共享具体实现或希望运行时强制抽象方法时才切换至 ABC。对于插件生态系统,“按形状符合”(Protocol)通常优于“按继承符合”(ABC)。选择取决于主要需求是定义形状,还是共享具体行为并强制继承层次结构。