我正在设计一个面向对象的数据结构,从用户的角度来看,它很容易处理,例如,通过方法链(aka Fluent interface)。但是,每次更改只应在对象上执行暂时:在该链中,但不能超出该链。
以下是 not 按预期工作的简化示例:
class C:
def __init__(self, num):
self.sum = num
def add(self, num=0):
self.sum += num
return self
number = C(23)
number.add(7).add(12).sum
# 42
number.sum
# 42 (but I expect: 23)
在这种情况下,.add()
会将永久更改为number
。但是,永久性更改应该是这样的:
# This is the only way how a user should make permanent changes:
number = number.add(4).add(12)
在临时范围内,我正在寻找一种在链终止后返回旧版number
的方法。在绝望的边缘,我可以想到丑陋的解决方案,如"实例复制":
class C2:
def __init__(self, num):
self.sum = num
def add(self, num=0):
self2 = C2(self.sum) # or equivalently: self2 = copy.deepcopy(self)
self2.sum += num
return self2
number = C2(23)
number.add(7).add(12).sum
# 42
number.sum
# 23
但是,我正在使用的实际类和对象包含大量数据,属性,方法甚至子类。所以我们应该避免在每个方法中复制实例,除了它涉及丑陋的代码。
有没有办法解决这个问题,例如通过(静默地)在链的第一个元素上只创建一个副本一次?或者通过销毁在链末端做出的任何改变? (请注意,真实世界"更改"涉及许多不同的,可通信的方法,而不仅仅是添加数字)
接受的解决方案应该在内部执行必要的操作,即不用打扰用户界面:
# These are NOT accepted solutions:
number.copy().add(4).add(12)
number.add(4).add(12).undo()
如果除了自我复制之外没有直接的解决方案,那么问题是:最优雅的方法是什么来维持代码可读性并保持较低的内存使用率?例如,通过自我复制功能装饰每一类方法?
答案 0 :(得分:1)
不是修改调用方法的对象,而是返回修改后的副本:
class C:
def __init__(self, num):
self.sum = num
def add(self, num=0):
return C(self.sum + num)
number = C(23)
assert number.add(7).add(12).sum == 42
assert number.sum == 23
有关此解决方案中内存处理的详细信息,请参阅此帖子的评论。此解决方案是解决问题的标准方法。