组合:我应该直接访问 "inner object's" 方法吗?
Composition: Should I access the "inner object's" methods directly?
我对 OOP 比较陌生,而且肯定还在学习。我想知道处理两个 class 时的最佳做法是什么,例如:
(我对一个旧电脑游戏的统计引擎进行了逆向工程,但我想这个主题与我的问题无关)
class Step(object):
def __init__(self):
self.input = 'G'
...more attributes...
def reset_input(self):
''' Reset input to None. '''
self.input = None
print '* Input reset.'
... more methods ...
然后我有 Player class,这是要控制的主要对象(至少在我的设计中):
class Player(object):
''' Represents a player. Accepts initial stats.'''
def __init__(self, step= 250, off= 13, dng= 50000, dist= 128, d_inc= 113):
self.route = []
self.step = Step(step=step, off=off, dng=dng, dist=dist, d_inc=d_inc)
self.original = copy.copy(self.step)
可以看到,Player中包含一个Step对象,代表下一步。
我发现有时我想从那个步骤 class 访问一个方法。
这种情况下,是不是给Player加个wrapper比较好,比如:
(如果我想访问reset_input()
):
class Player(object):
...
def reset_input(self):
self.step.reset_input()
然后播放器重置输入值:
p = Player()
p.reset_input()
或者直接访问 reset_input()
会更好吗:
p = Player()
p.step.reset_input()
似乎添加包装器只是复制代码。这也很烦人,因为我需要访问相当多的 Step 方法。
那么,当使用组合时(我认为这是正确的术语),直接访问 'inner' 对象方法是一种好习惯吗?
如果出现以下情况,我认为您应该在 OOP 中应用额外的抽象层:
- 您预见自己稍后会更新代码;和
- 该代码将在多个地方使用。
在这种情况下,假设您使用此方法:
def reset_input(self):
self.step.reset_input()
然后您在代码中的多个位置调用它。稍后,您决定要在对 reset_input
的所有调用之前执行操作 x()
,将可选参数 y
传递给 reset_input
,然后执行操作 z()
在那之后。然后按如下方式更新方法很简单:
def reset_input(self):
self.x()
self.step.reset_input(self.y)
self.z()
并且代码 将随处更改 只需敲击几下。想象一下,如果您因为没有使用包装函数而不得不更新多个地方的所有调用,您将面临的噩梦。
如果您确实预见到自己使用包装器将更改应用于您的代码,则您应该应用包装器。这将使您的代码更易于维护。如评论中所述,此概念称为 encapsulation;它允许您使用隐藏实现细节的接口,以便您可以随时轻松更新实现,并且它会以非常简单的方式通用地更改代码。
这总是一个权衡。看看Law of Demeter。它描述了您的情况以及不同解决方案的优缺点。
我对 OOP 比较陌生,而且肯定还在学习。我想知道处理两个 class 时的最佳做法是什么,例如:
(我对一个旧电脑游戏的统计引擎进行了逆向工程,但我想这个主题与我的问题无关)
class Step(object):
def __init__(self):
self.input = 'G'
...more attributes...
def reset_input(self):
''' Reset input to None. '''
self.input = None
print '* Input reset.'
... more methods ...
然后我有 Player class,这是要控制的主要对象(至少在我的设计中):
class Player(object):
''' Represents a player. Accepts initial stats.'''
def __init__(self, step= 250, off= 13, dng= 50000, dist= 128, d_inc= 113):
self.route = []
self.step = Step(step=step, off=off, dng=dng, dist=dist, d_inc=d_inc)
self.original = copy.copy(self.step)
可以看到,Player中包含一个Step对象,代表下一步。
我发现有时我想从那个步骤 class 访问一个方法。 这种情况下,是不是给Player加个wrapper比较好,比如:
(如果我想访问reset_input()
):
class Player(object):
...
def reset_input(self):
self.step.reset_input()
然后播放器重置输入值:
p = Player()
p.reset_input()
或者直接访问 reset_input()
会更好吗:
p = Player()
p.step.reset_input()
似乎添加包装器只是复制代码。这也很烦人,因为我需要访问相当多的 Step 方法。
那么,当使用组合时(我认为这是正确的术语),直接访问 'inner' 对象方法是一种好习惯吗?
如果出现以下情况,我认为您应该在 OOP 中应用额外的抽象层:
- 您预见自己稍后会更新代码;和
- 该代码将在多个地方使用。
在这种情况下,假设您使用此方法:
def reset_input(self):
self.step.reset_input()
然后您在代码中的多个位置调用它。稍后,您决定要在对 reset_input
的所有调用之前执行操作 x()
,将可选参数 y
传递给 reset_input
,然后执行操作 z()
在那之后。然后按如下方式更新方法很简单:
def reset_input(self):
self.x()
self.step.reset_input(self.y)
self.z()
并且代码 将随处更改 只需敲击几下。想象一下,如果您因为没有使用包装函数而不得不更新多个地方的所有调用,您将面临的噩梦。
如果您确实预见到自己使用包装器将更改应用于您的代码,则您应该应用包装器。这将使您的代码更易于维护。如评论中所述,此概念称为 encapsulation;它允许您使用隐藏实现细节的接口,以便您可以随时轻松更新实现,并且它会以非常简单的方式通用地更改代码。
这总是一个权衡。看看Law of Demeter。它描述了您的情况以及不同解决方案的优缺点。