2016-11-16 16 views
1

Я проектирую объектно-ориентированную структуру данных, которая должна быть прост в обращении с точки зрения пользователя, например, путем цепочки (aka Fluent interface). Однако каждое изменение должно действовать только временно на объект: внутри этой цепи, но не за этой цепью.
Вот упрощенный пример, который делает не работы по назначению:Сохранять изменения в объекте, временном во время цепочки методов.

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 

Однако классы actuall и объекты, с которыми я работаю, содержит огромное количество данных, атрибуты, методы, и даже подклассы. Поэтому нам следует избегать копирования экземпляра в каждом отдельном методе, кроме того, что он включает в себя уродливый код.

Существуют ли способы решения этой проблемы, например. (тихо), создавая единственную копию только один раз в первом элементе цепочки? Или путем уничтожения любых изменений, сделанных в конце цепи? (Обратите внимание, что в реальном мире «изменения» включают много различных, коммутируемых других, чем просто добавление чисел методы)

обслуживаемого решение должно выполнить необходимые операции внутри, то есть, не беспокоя пользовательский интерфейс:

# These are NOT accepted solutions: 
number.copy().add(4).add(12) 
number.add(4).add(12).undo() 

Если нет прямого решения, кроме саморепликации, вопрос будет следующим: Какой самый элегантный способ сделать это, который поддерживает считывание кода и снижает потребление памяти? Например, украшая каждый метод класса функцией самовоспроизводства?

+0

Я не вижу, как было бы возможно, чтобы объект автоматически обнаружил конец «временной области» - за исключением, возможно, написания собственного языка на основе python и даже тогда ... FWIW, весь «свободный интерфейс» «Реализации, которые я видел до сих пор, либо мутируют объект на месте, либо возвращают копию. –

ответ

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 

Для получения дополнительной информации об обработке в этом растворе памяти см комментариев этого сообщения. Это решение является стандартным способом решения вашей проблемы.

+0

К сожалению, это решение уже было задано в вопросе. – Martin

+0

Тогда я говорю вам, что это стандартная практика, а не грязный хак. –

+0

Я знаю, что это стандарт для многих применений. Но является ли это также рекомендуемой (или единственной) стратегией для экземпляров большого размера? Я боюсь, что это резко увеличит использование памяти: S Или python автоматически удаляет все экземпляры, когда цепочка заканчивается? – Martin