使用 OOP 和代理模式构建字符串
我发现 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,因此我可以以任何顺序调用它们,并且可以无限次调用它们。
其次,代理对象,如果不是 perform 方法,它将调用主体的方法,该方法调用对象来查看结果字符串。
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:抱歉我的英语,这不是我的主要语言。
I find it very interesting the way how SQLAlchemy constructing query strings, eg:
(Session.query(model.User)
.filter(model.User.age > 18)
.order_by(model.User.age)
.all())
As far as I can see, there applied some kind of Proxy Pattern. In my small project I need to make similar string construction using OOP approach. So, I tried to reconstitute this behavior.
Firstly, some kind of object, one of plenty similar objects:
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
All methods of this object return self, so I can call them in any order and unlimited number of times.
Secondly, proxy object, that will call subject's methods if it's not a perform method, which calls object to see the resulting string.
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()
And finally:
>>> obj = SomeObject()
>>> p = Proxy(obj)
>>> print p.a().a().b().perform()
a a b
What can you say about this implementation? Is there better ways to make the desirable amount of classes that would make such a string cunstructing with the same syntax?
PS: Sorry for my english, it's not my primary language.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
实际上,您看到的不是代理模式,而是 构建器模式,是的,您的实现是恕我直言,它是经典的(使用 Fluent 界面 模式)。
Actually what you are looking at is not a proxy pattern but the builder pattern, and yes your implementation is IMHO is the classic one (using the Fluent interface pattern).
我不知道 SQLAlchemy 是做什么的,但我会通过让
Session.query()
方法返回一个Query
对象,并使用filter( )
、order_by()
、all()
等。这些方法中的每一个都只返回一个新的Query
对象,同时考虑到应用的更改。这允许像第一个示例中那样进行方法链接。您自己的代码示例有很多问题。一个例子
I don't know what SQLAlchemy does, but I would implement the interface by having the
Session.query()
method return aQuery
object with methods likefilter()
,order_by()
,all()
etc. Each of these methods simply returns a newQuery
object taking into account the applied changes. This allows for method chaining as in your first example.Your own code example has numerous problems. One example