nam*_*ked 47 python design-patterns builder-pattern
在Java中,您可以使用构建器模式提供更具可读性的方法来实例化具有许多参数的类.在构建器模式中,构造一个配置对象,其中包含设置命名属性的方法,然后使用它来构造另一个对象.
Python中的等价物是什么?是模仿相同实现的最佳方法吗?
Mec*_*ail 90
设计模式通常可以用内置语言功能替换.
你说"我想要更具可读性"意味着"实例化一个包含许多参数的类".在Java的情况下:
但是Python支持命名参数,所以这不是必需的.你可以定义一个类的构造函数:
class SomeClass(object):
def __init__(self, foo="default foo", bar="default bar", baz="default baz"):
# do something
Run Code Online (Sandbox Code Playgroud)
并使用命名参数调用它:
s = SomeClass(bar=1, foo=0)
Run Code Online (Sandbox Code Playgroud)
请注意,您可以自由地重新排序和省略参数,就像使用Java中的构建器一样,您可以省略或重新排序set
对构建器对象上的方法的调用.
另外值得一提的是,Python的动态特性使您可以更自由地构建对象(使用__new__
等),这可以取代构建器模式的其他用途.
你可以collections.namedtuple
用作你的配置对象.namedtuple()
返回一个表示元组的新类型,每个元素的参数都有一个给定的名称,而不必编写样板类.您可以使用与Java构建器类似的方式使用结果类型的对象.(感谢Paul McGuire的建议.)
StringBuilder
相关模式是Java的StringBuilder,它用于有效地构建(不可变)String
阶段.在Python中,这可以替换为str.join
.例如:
final StringBuilder sb = new StringBuilder();
for(int i = 0; i < 100; i++)
sb.append("Hello(" + i + ")");
return sb.toString();
Run Code Online (Sandbox Code Playgroud)
可以替换为
return "".join("Hello({})".format(i) for i in range(100))
Run Code Online (Sandbox Code Playgroud)
Mal*_*ina 34
OP通过将Builder模式转换为特定于Java的模式来设置自己的下降.不是.它出现在Gang of Four的书中,可能与任何面向对象的语言相关.
不幸的是,即使维基百科关于Builder模式的文章也没有给予足够的信任.它不仅仅对代码优雅有用.构建器模式是创建不可变对象的好方法,这些对象在使用之前需要是可变的.不可变状态在功能范例中尤其重要,使得Builder成为python的优秀面向对象模式.
我在下面使用collections.namedtuple提供了一个示例Builder + ImmutableObject实现,从" 如何在python中创建不可变对象 "中借用和修改.我让Builder非常简单.但是,可以提供setter函数,返回Builder本身以允许调用链接.或者可以在Builder中使用@property语法来提供在设置之前检查属性有效性的属性设置器.
from collections import namedtuple
IMMUTABLE_OBJECT_FIELDS = ['required_function_result', 'required_parameter', 'default_parameter']
class ImmutableObjectBuilder(object):
def __init__(self, required_function, required_parameter, default_parameter="foo"):
self.required_function = required_function
self.required_parameter = required_parameter
self.default_parameter = default_parameter
def build(self):
return ImmutableObject(self.required_function(self.required_parameter),
self.required_parameter,
self.default_parameter)
class ImmutableObject(namedtuple('ImmutableObject', IMMUTABLE_OBJECT_FIELDS)):
__slots__ = ()
@property
def foo_property(self):
return self.required_function_result + self.required_parameter
def foo_function(self):
return self.required_function_result - self.required_parameter
def __str__(self):
return str(self.__dict__)
Run Code Online (Sandbox Code Playgroud)
用法示例:
my_builder = ImmutableObjectBuilder(lambda x: x+1, 2)
obj1 = my_builder.build()
my_builder.default_parameter = "bar"
my_builder.required_parameter = 1
obj2 = my_builder.build()
my_builder.required_function = lambda x: x-1
obj3 = my_builder.build()
print obj1
# prints "OrderedDict([('required_function_result', 3), ('required_parameter', 2), ('default_parameter', 'foo')])"
print obj1.required_function_result
# prints 3
print obj1.foo_property
# prints 5
print obj1.foo_function()
# prints 1
print obj2
# prints "OrderedDict([('required_function_result', 2), ('required_parameter', 1), ('default_parameter', 'bar')])"
print obj3
# prints "OrderedDict([('required_function_result', 0), ('required_parameter', 1), ('default_parameter', 'bar')])"
Run Code Online (Sandbox Code Playgroud)
在这个例子中,我创建了三个ImmutableObjects,它们都有不同的参数.我已经让调用者能够以构建器的形式复制,修改和传递可变配置,同时仍然保证构建对象的不变性.在ImmutableObjects上设置和删除属性会引发错误.
结论:构建器是一种传递具有可变状态的东西的好方法,当你准备好使用它时,它提供了一个具有不可变状态的对象.或者,换句话说,构建器是提供属性设置器同时仍然确保不可变状态的好方法.这在功能范例中特别有价值.
Cow*_*bop 13
我不同意@MechanicalSnail.我认为类似于海报所引用的构建器实现在某些情况下仍然非常有用.命名参数只允许您简单地设置成员变量.如果你想做一些稍微复杂的事情,那你就不走运了.在我的示例中,我使用经典构建器模式来创建数组.
class Row_Builder(object):
def __init__(self):
self.row = ['' for i in range(170)]
def with_fy(self, fiscal_year):
self.row[FISCAL_YEAR] = fiscal_year
return self
def with_id(self, batch_id):
self.row[BATCH_ID] = batch_id
return self
def build(self):
return self.row
Run Code Online (Sandbox Code Playgroud)
使用它:
row_FY13_888 = Row_Builder().with_fy('FY13').with_id('888').build()
Run Code Online (Sandbox Code Playgroud)
小智 7
我刚刚遇到构建这种模式的需要,并偶然发现了这个问题。我意识到这个问题有多老了,但不妨添加我的构建器模式版本,以防对其他人有用。
我相信使用装饰器来指定构建器类是在 python 中实现构建器模式的最符合人体工程学的方式。
def buildermethod(func):
def wrapper(self, *args, **kwargs):
func(self, *args, **kwargs)
return self
return wrapper
class A:
def __init__(self):
self.x = 0
self.y = 0
@buildermethod
def set_x(self, x):
self.x = x
@buildermethod
def set_y(self, y):
self.y = y
a = A().set_x(1).set_y(2)
Run Code Online (Sandbox Code Playgroud)
构建器和构造函数不是一回事,构建器是一个概念,构造函数是一种编程语法。没有必要比较两者。
因此,确保您可以使用构造函数、类方法或专用类来实现构建器模式,不会发生冲突,请使用适合您情况的一种。
从概念上讲,构建器模式将构建过程与最终对象解耦。举一个现实世界中建造房屋的例子。建造者可能会使用大量工具和材料来建造房屋,但最终的房屋在建造后不需要放置这些工具和多余的材料。
例子:
woodboards = Stores.buy(100)
bricks = Stores.buy(200)
drills = BuilderOffice.borrow(4)
house = HouseBuilder.drills(drills).woodboards(woodboards).bricks(bricks).build()
Run Code Online (Sandbox Code Playgroud)