4

我发现 SQLAlchemy 构造查询字符串的方式非常有趣,例如:

(Session.query(model.User)
        .filter(model.User.age > 18)
        .order_by(model.User.age)
        .all())

据我所见,那里应用了某种代理模式。在我的小项目中,我需要使用 OOP 方法进行类似的字符串构造。所以,我试图重构这种行为。

首先,某种对象,许多相似对象之一:

class SomeObject(object):
    items = None

    def __init__(self):
        self.items = []

    def __call__(self):
        return ' '.join(self.items) if self.items is not None else ''

    def a(self):
        self.items.append('a')
        return self

    def b(self):
        self.items.append('b')
        return self

该对象的所有方法都返回self,因此我可以按任意顺序调用它们,并且次数不受限制。

其次,代理对象,如果它不是一个执行方法,它将调用主体的方法,它调用对象来查看结果字符串。

import operator

class Proxy(object):
    def __init__(self, some_object):
        self.some_object = some_object

    def __getattr__(self, name):
        self.method = operator.methodcaller(name)
        return self

    def __call__(self, *args, **kw):
        self.some_object = self.method(self.some_object, *args, **kw)
        return self

    def perform(self):
        return self.some_object()

最后:

>>> obj = SomeObject()
>>> p = Proxy(obj)
>>> print p.a().a().b().perform()
a a b

你对这个实现有什么看法?有没有更好的方法来制作所需数量的类,从而使这样的字符串具有相同的语法

PS:对不起我的英语,它不是我的主要语言。

4

2 回答 2

3

实际上,您看到的不是代理模式,而是构建器模式,是的,恕我直言,您的实现是经典的(使用Fluent 接口模式)。

于 2011-10-19T14:25:53.573 回答
1

我不知道 SQLAlchemy 做了什么,但我会通过让Session.query()方法返回一个带有、等Query方法的对象来实现接口。这些方法中的每一个都只是返回一个新对象,并考虑到应用的更改。这允许像您的第一个示例中那样进行方法链接。filter()order_by()all()Query

您自己的代码示例有很多问题。一个例子

obj = SomeObject()
p = Proxy(obj)
a = p.a
b = p.b
print a().perform()  # prints b
于 2011-10-19T14:17:36.757 回答