在不破坏兼容性的情况下合并两个 Python API
Merging two Python APIs without breaking compatability
场景如下:
存储系统 A
(Java) 是默认设置,并且具有 Python API API_A
。最近引入了存储系统 B
(Java/C++),但没有 Python API。人们 "somehow" 让 B
与 API_A
一起工作,但它非常慢,尤其是随着规模的增加。因为,这是 Python API 的唯一选择,现在很多代码都依赖 API_A
与 B
交互。
来自存储系统 B
的团队现在有 Python API、API_B
。 API_B
显然更有效率。但是,API_A
和 API_B
之间有很多差异。例如,列表目录方法 return 具有完全不同字段的对象。 API_B
不允许递归删除目录,但 API_A
允许。等等...
问题:
在不破坏兼容性的情况下合并两个 API 的最佳方法是什么?特别是API_A
已经在使用了,那么透明的把API_B
集成进去的最好方法是什么?
我认为创建装饰器不会起作用,因为方法签名在 API 之间有所不同。 API_A
中有一些方法在 API_B
中不存在。 (提高 NotImplementedException
是这里唯一的选择)。
我能想到的唯一解决方案是天真的解决方案,我必须在 API_A
:
中的每个函数中进行检查
if self.isStorageA:
return method_of_A(args)
else:
return method_of_B(args, args)
我正在寻找一种更好、更易于维护的方法来做到这一点。非常感谢任何帮助!
为 API B 编写一个“看起来像”API A
的包装器库
特别是,它必须提供具有完全相同签名的完全相同的方法。如果 API B 没有实现某些功能(如递归枚举),则包装器必须根据 API B 重新实现此功能。例如,您可以编写一个枚举当前目录的函数,然后每个子目录,以此类推递归地替换 API A 的本机功能。如果不可能做到这一点(也就是说,如果 API A 提供了一些功能而不能完全用 API B 完成),那么 API B 不是 API A 的合适替代品,你不应该继续你的计划。
您还应该为您的包装器编写一系列单元测试,以确保它的行为与 API A 在各种条件下的行为相同,特别是在边缘情况下。如果 A 已经有单元测试,那么就使用那些。
最后,一旦您确定包装纸与 A 没有区别,您就可以用包装纸替换 A。只需替换模块和包就足够简单了,但是如果由于某种原因这对您不起作用,您可以替换 sys.modules
中的 A 以确保 A 的导入得到包装器。
场景如下:
存储系统 A
(Java) 是默认设置,并且具有 Python API API_A
。最近引入了存储系统 B
(Java/C++),但没有 Python API。人们 "somehow" 让 B
与 API_A
一起工作,但它非常慢,尤其是随着规模的增加。因为,这是 Python API 的唯一选择,现在很多代码都依赖 API_A
与 B
交互。
来自存储系统 B
的团队现在有 Python API、API_B
。 API_B
显然更有效率。但是,API_A
和 API_B
之间有很多差异。例如,列表目录方法 return 具有完全不同字段的对象。 API_B
不允许递归删除目录,但 API_A
允许。等等...
问题:
在不破坏兼容性的情况下合并两个 API 的最佳方法是什么?特别是API_A
已经在使用了,那么透明的把API_B
集成进去的最好方法是什么?
我认为创建装饰器不会起作用,因为方法签名在 API 之间有所不同。 API_A
中有一些方法在 API_B
中不存在。 (提高 NotImplementedException
是这里唯一的选择)。
我能想到的唯一解决方案是天真的解决方案,我必须在 API_A
:
if self.isStorageA:
return method_of_A(args)
else:
return method_of_B(args, args)
我正在寻找一种更好、更易于维护的方法来做到这一点。非常感谢任何帮助!
为 API B 编写一个“看起来像”API A
的包装器库特别是,它必须提供具有完全相同签名的完全相同的方法。如果 API B 没有实现某些功能(如递归枚举),则包装器必须根据 API B 重新实现此功能。例如,您可以编写一个枚举当前目录的函数,然后每个子目录,以此类推递归地替换 API A 的本机功能。如果不可能做到这一点(也就是说,如果 API A 提供了一些功能而不能完全用 API B 完成),那么 API B 不是 API A 的合适替代品,你不应该继续你的计划。
您还应该为您的包装器编写一系列单元测试,以确保它的行为与 API A 在各种条件下的行为相同,特别是在边缘情况下。如果 A 已经有单元测试,那么就使用那些。
最后,一旦您确定包装纸与 A 没有区别,您就可以用包装纸替换 A。只需替换模块和包就足够简单了,但是如果由于某种原因这对您不起作用,您可以替换 sys.modules
中的 A 以确保 A 的导入得到包装器。