在 Java 中,您可以使用构建器模式来提供一种更易读的方法来实例化具有许多参数的类。在构建器模式中,使用设置命名属性的方法构造一个配置对象,然后使用它来构造另一个对象。
Python中的等价物是什么?模仿相同实现的最佳方法是什么?
在 Java 中,您可以使用构建器模式来提供一种更易读的方法来实例化具有许多参数的类。在构建器模式中,使用设置命名属性的方法构造一个配置对象,然后使用它来构造另一个对象。
Python中的等价物是什么?模仿相同实现的最佳方法是什么?
设计模式通常可以用内置的语言特性代替。
你说“我想要一个更易读的“手段”来实例化一个有很多参数的类。”。在 Java 的情况下:
但是 Python 支持命名参数,所以这不是必需的。您可以只定义一个类的构造函数:
class SomeClass(object):
def __init__(self, foo="default foo", bar="default bar", baz="default baz"):
# do something
并使用命名参数调用它:
s = SomeClass(bar=1, foo=0)
请注意,您可以自由地重新排序和省略参数,就像使用 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();
可以替换为
return "".join(f"Hello({i})" for i in range(100))
OP 通过将 Builder 模式转换为特定于 Java 的方式来为自己做好准备。它不是。它在四人帮的书中,并且可能与任何面向对象的语言相关。
不幸的是,即使是关于 Builder 模式的 Wikipedia 文章也没有给予足够的信任。它不仅仅对代码优雅有用。构建器模式是创建不可变对象的好方法,这些对象在使用之前必须是可变的。不可变状态在函数范式中尤其重要,这使得 Builder 成为 Python 的优秀面向对象模式。
我在下面使用collections.namedtuple提供了一个示例 Builder + ImmutableObject 实现,从“ How to make an immutable object in python ”中借用和修改。我让 Builder 相当简单。但是,可以提供返回 Builder 本身的 setter 函数以允许调用链。或者可以在 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__)
示例用法:
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')])"
在这个例子中,我创建了三个 ImmutableObjects,它们都具有不同的参数。我赋予调用者以构建器的形式复制、修改和传递可变配置的能力,同时仍保证构建对象的不变性。在 ImmutableObjects 上设置和删除属性会引发错误。
底线:构建器是传递具有可变状态的东西的好方法,当您准备好使用它时,它为对象提供了不可变状态。或者,换句话说,构建器是提供属性设置器同时仍确保不可变状态的好方法。这在功能范式中尤其有价值。
我不同意@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
使用它:
row_FY13_888 = Row_Builder().with_fy('FY13').with_id('888').build()
我刚刚遇到了构建这种模式的需求,偶然发现了这个问题。我意识到这个问题有多老了,但不妨添加我的构建器模式版本,以防它对其他人有用。
我相信使用装饰器来指定构建器类是在 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)
Java 中的构建器模式可以通过使用以下变体在 python 中轻松实现:
MyClass(self, required=True, someNumber=<default>, *args, **kwargs)
whererequired
和someNumber
是一个示例,显示具有默认值的所需参数,然后在处理可能存在的情况时读取可变参数None
如果您之前没有使用过变量参数,请参考这里
builder和constructor不是一回事,builder是一个概念,constructor是一种编程语法。没有必要将两者进行比较。
因此,请确保您可以使用构造函数、类方法或专用类来实现构建器模式,没有冲突,请使用适合您情况的任何一种。
从概念上讲,构建器模式将构建过程与最终对象分离。以建造房屋的真实世界为例。建造者可能会使用很多工具和材料来建造房屋,但最终的房屋在建造后不需要那些工具和多余的材料。
例子:
woodboards = Stores.buy(100)
bricks = Stores.buy(200)
drills = BuilderOffice.borrow(4)
house = HouseBuilder.drills(drills).woodboards(woodboards).bricks(bricks).build()