我正在为SOAP API构建Python API包装器。我需要设计一组API类,其中包含不同数量的动词操作(add
,get
,list
,remove
等。此外,由于SOAP API中对象的性质,这些可能还包含来自(sync
,options
,apply
,restart
和{的子集的其他方法。 {1}})。每个动词的内部意味着极少数情况需要覆盖并且很容易被继承。我的问题是,某些端点是单例,或者出于任何原因可能只支持这些方法的子集。意思是:
EndpointA
reset
EndpointB
get
,add
,get
,list
remove
和apply
EndpointC
restart
和add
EndpointD
get
,add
,get
,list
remove
,apply
,restart
我有超过100个端点。大多数人都有一个共同的主题:
reset
,add
,get
,list
然而,有很多例外。
在我目前的设计中,所有端点都使用remove
属性进行实例化,该属性控制线路上的SOAP连接,请求和响应。我正在寻找一种灵活创建类设计的方法,允许我在不需要复制代码或无意中继承API端点不支持的方法的情况下放入方法。
平坦的继承是有问题的,因为我没有足够的灵活性来处理方法的所有排列。
Client
我在想mixins,但正如你所看到的,动词方法依赖于普通客户端。根据我的理解,mixins应该只从BaseAPI(object):
def __init___(self, client):
self.client = client
ChildAPI(BaseAPI):
def __init___(self, client):
super().__init__(client)
def get(self, **kwargs):
soap_method = methodcaller("".join(["get", self.__class__.__name__]), **kwargs)
resp = soap_method(self.client.service)
return resp
def list(self, **kwargs):
soap_method = methodcaller("".join(["list", self.__class__.__name__]), **kwargs)
resp = soap_method(self.client.service)
return stuff
# same for add and remove...
EndpointA(BaseAPI):
def __init___(self, client):
super().__init__(client)
# now i have a problem as i only wanted the get method...
EndpointD(BaseAPI):
def __init___(self, client):
super().__init__(client)
# I have all the methods I wanted...
继承。
有人可以建议如何布置我的班级设计以尽可能地促进重复使用,并避免缺乏灵活性吗?
答案 0 :(得分:1)
我是否理解,如果端点支持,方法的实现对于所有端点都是一样的?在这种情况下,您可以使用一个包含受支持的方法名称的小列表来解决它,并被每个Endpoint子类覆盖:
import functools
class BaseAPI:
def __init___(self, client):
self.client = client
class ChildAPI(BaseAPI):
supported_methods = ["add", "get", "list", "remove", "apply", "restart", "reset"]
@classmethod
def assert_supported(cls, func):
"""Decorator looks up func's name in self.supported_methods."""
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
if func.__name__ not in self.supported_methods:
raise AttributeError("This Endpoint does not support this method.")
return func(self, *args, **kwargs)
return wrapper
# implementation of methods here, each decorated with @assert_supported
@assert_supported
def get(self, **kwargs):
soap_method = methodcaller("".join(["get", self.__class__.__name__]), **kwargs)
resp = soap_method(self.client.service)
return resp
@assert_supported
def list(self, **kwargs):
soap_method = methodcaller("".join(["list", self.__class__.__name__]), **kwargs)
resp = soap_method(self.client.service)
return stuff
class EndpointA(BaseAPI):
supported_methods = ["get"]
class EndpointB(BaseAPI):
supported_methods = ["add", "get", "list", "remove", "apply", "restart"]
class EndpointC(BaseAPI):
supported_methods = ["add", "get"]
class EndpointD(BaseAPI):
pass # no change to supported_methods => all of them
这减少了将基本方法适应每个类一行的工作量,并且仍然可以灵活地添加所需的任何代码。