我正在使用boto3设置一些AWS路由。
在AWS环境中,我们希望有一个负责将路线戳入EC2 VPC的课程。在非AWS环境中,它将做其他事情。
在传统的OOP方法中,我将具有一个定义announce_route
方法的接口,并创建AwsRouting或FoobarRouting的具体实例等。
伪代码说明方案:
interface Routing
function announceRoute()
class AWSRouting implements Routing
class RouteAnnouncer
function constructor(Routing routing)
我会根据某些环境变量或配置选项将适当的路线注入播音员。
用依赖注入来实现这种适配器模式的Pythonic方法是什么?到目前为止
这就是我到目前为止所拥有的:
class RouteAnnouncer:
def __init__(self, adapter):
self.adapter = adapter
def announce_route(self, ip_addr):
self.adapter.announce_route(ip_addr)
class AnnounceRouteContract:
def announce_route(self, ip_addr):
raise NotImplementedError
class AWSRouting(AnnounceRouteContract):
def announce_route(self, ip_addr):
pass
class StandardRouting(AnnounceRouteContract):
def announce_route(self, ip_addr):
pass
所以我认为我真正缺少的是如何告诉用户RouteAnnouncer
中的适配器是AnnounceRouteContract
的实例。
您不需要做几乎如此愚蠢的事情,例如创建一堆"接口"。在Python中,您的界面取决于您的行为方式。通常称为"鸭子打字",因为如果您看起来像鸭子,您像鸭子一样行走,然后像鸭子一样颤抖,那么您必须是鸭子。
我们不在乎您是是否真的 穿着鸭子服装的人,还是鸭子的纸板切口或机器人鸭。这完全是无关的。
在您的情况下,您的全部真正关心的是announce_route(ip_addr)
是您可以调用的东西。当然,最终您希望它将真正设置路线,但是您知道,这就是测试的目的。
您 May 想做的就是拥有一个看起来像这样的工厂:
class MyRouteAnnouncer:
def __init__(self):
... # whatever you need to do
def announce_route(self, ip_addr):
... # do what you need to do
def get_router():
if env.is_aws():
return boto3
elif env.is_something_else():
return MyRouteAnnouncer()
else:
raise Exception('Unknown environment')
,然后任何称为get_router()
功能的函数都会获取适当的路由器并在其上调用announce_route(ip_addr)
。
您不能强迫类用户仅将本机Python的特定类实例放置(在Python 3.6中似乎已实现)。您可以为用户提供一个提示,以便IDE如果没有预期的类别的实例,可以抱怨:
class RouteAnnouncer:
def __init__(self, adapter):
"""
:param AnnounceRouteContract adapter: Route adapter
self.adapter = adapter
还制作合同摘要以及announce_route
的方法来强制用户实施它。
您也可以使用ISSUBCLASS内置功能检查适配器是否为预期合同的实例
在Python World中,无法指定参数类型。我认为一种适当的方法是使用断言在内部函数中检查适配器类型。
class RouteAnnouncer:
def __init__(self, adapter):
assert isinstance(adapter, AnnounceRouteContract)
self.adapter = adapter