编写包装类或函数时如何避免样板?

时间:2017-04-07 14:57:16

标签: python python-2.7

我发现自己在许多实现类似接口的后端类上编写了一个包装类。基本版本看起来像这样:

class Wrapper(BackendInterface):
    def __init__(self, **kwargs):
        # Instantiate/initialize backend classes
        self._b1 = BackendOne(...)
        self._b2 = BackendTwo(...)
        ...

    def _select_backend(self, ...):
        # Select backend based on runtime requirements
        if condition_one:
            return self._b1
        elif condition_two:
            return self._b2
        ...

    def method_one(self, foo, bar, baz, alpha, beta, gamma, delta, ...):
        b = self._select_backend(...)
        b.method_one(foo, bar, baz, alpha, beta, gamma, delta, ...)

    def method_two(self, a, b, c, d, ...):
        b = self._select_backend(...)
        b.method_two(a, b, c, d, ...)

    ...

如上所示,许多(但不是全部)方法归结为后端选择,然后在后端对象上调用相同的方法。在许多情况下,甚至方法签名也是相同的。有没有办法避免这种样板乱七八糟?

我考虑过在每个方法的顶部使用locals()。

...
def method_one(self,  foo, bar, baz, alpha, beta, gamma, delta, ...):
    args = locals() # Must be the first line!
    del args['self']
    b = self._select_backend(...)
    b.method_one(**args)
...

我相信使用检查模块可以获得类似的结果。

但这种方法存在一些问题。 1.还有很多样板。 2. locals()调用必须在第一行。我很确定有人会尝试在某个时候“优化”该方法并搞砸它。

我可以使用更好的方法吗?

我也有兴趣了解如何在Java中处理这种情况。

注意:如果重要的话,我正在使用Python 2.7.11。

编辑:删除了Java标记。我将分别为Java提出这个问题。这样Python开发人员就不必阅读Java代码,反之亦然。

2 个答案:

答案 0 :(得分:0)

当然,您可以在方法中接受*args - 或*args, **kwargs - 并将其传递到后端?

def method_one(self, *args, **kwargs):
    b = self._select_backend(...)
    b.method_one(*args, **kwargs)

答案 1 :(得分:0)

这是我最终为Python做的事情

class Wrapper(BackendInterface):
    def __init__(self, **kwargs):
        # Instantiate/initialize backend classes
        self._b1 = BackendOne(...)
        self._b2 = BackendTwo(...)
        ...

    def __dispatch_to_backend(method):
        @functools.wraps(method, updated=[])
        def wrapper(self, *args, **kwargs):
            method_impl = getattr(self._select_backend(...), method.__name__)
            return method_impl(*args, **kwargs)

        return wrapper

    def _select_backend(self, ...):
        # Select backend based on runtime requirements
        if condition_one:
            return self._b1
        elif condition_two:
            return self._b2
        ...

    method_one = __dispatch_to_backend(BackendInterface.method_one)
    method_one = __dispatch_to_backend(BackendInterface.method_two)

    ...

我猜这是免费的样板文件。