我正在编写一个Python,其中我有一个主要类(PlayerModel),它有另外两个类作为成员(StateModel和ActionModel)。我想知道,初始化这种复合类的正确方法是什么?
目前。我将分别创建成员实例,类的__init__方法如下所示:
def __init__(self, state_model, action_model):
self.state_model = state_model
self.action_model = action_model但是,这意味着类在编译时不知道成员的类型(例如,我丢失了自动完成,这很烦人)。
当然,我可以实例化主类中的成员,但这意味着我必须始终将他们的参数传递给主类构造函数,将其转换为具有5-6参数的方法,我不喜欢这些参数(Bob叔叔也不喜欢)。
对于这个问题,有比将成员类的参数聚合为命名元组更优雅的解决方案吗?
发布于 2016-02-19 15:42:45
首先,请注意Python是一种动态语言。不管您使用什么解决方案,“成员的类型在编译时都不为类所知”,因为Python没有为变量或类成员分配类型的静态类型系统。好的自动完成是有价值的,但是你不应该把你的设计押在你的编辑器的局限性上。
在类内部或外部实例化字段时,有几个重要的权衡。
对我来说,决定性的问题是,内部对象是可能在运行时被选中的依赖项,还是太大,需要进行隔离测试。在你的例子中,答案可能是“是”。在外部实例化这些类要合理得多。
player_model = PlayerModel(
state_model=StateModel(...),
action_model=ActionModel(...))而不是将其他模型的实例化添加到它已经拥有的所有职责中。特别是,实例化构造函数中的所有内容的策略会导致更大、更臃肿的构造函数,从而进一步查找使用链。这不仅是计算参数的问题,也是有关分离关注的问题。
如果调用方负责实例化所有依赖项是不合理的,我有时会创建一个工厂来执行此操作:
class Dependencies(object):
def __init__(self, global_configuration):
...
def new_player_model(self, ...):
return PlayerModel(
state_model=self.new_state_model(...),
action_model=self.new_action_model(...))
def new_state_model(self, ...): return StateModel(...)
def new_action_model(self, ...): return ActionModel(...)然后:
deps = Dependencies(...)
player_model = deps.new_player_model(...)通常,许多构造函数参数只是必须满足的各种依赖关系。Dependencies对象中的工厂方法只需转发其他参数,因为依赖项可以在内部管理。在这种情况下,集中依赖管理可能非常有用。
如果大量的争论是不可避免的,那么有几种策略可以解决这一问题。最重要的是内置Python:命名参数。在声明函数def foo(a, b, c): ...时,可以以foo("a", c="c", b="b")的形式调用它。注意,这些标签是可选的,顺序是任意的,如果忘记了任何必需的参数,Python将抛出一个错误。这使得您的参数的变量名非常重要,因为它们可能用于命名参数。使用命名参数,管理大量的参数是合理的。在这里,针对“Bob叔叔”和其他参数的建议只适用于局限性,因为它们的建议主要针对Java等缺乏命名参数的语言。
但是,命名参数并不能解决所有问题(matplotlib.pyplot是我最喜欢的反例)。通常情况下,会有自然的参数组。某些参数只能一起使用(例如,x和y坐标)。然后,我们可以引入包含这些参数的小对象,而不执行其他操作。应用于您的情况,我们可能有StateModelArgs和ActionModelArgs或其他分组。然后调用者提供这些参数,但是实际的对象是从类中的这些参数实例化的。这种策略有一些优点,例如在参数对象中可以更容易地进行验证,但它们也可能提供的值太少,因此更容易直接实例化实际对象。
所以使用哪种策略在很大程度上取决于具体的情况,而这两种选择都是有意义的。
https://softwareengineering.stackexchange.com/questions/310538
复制相似问题