Лучший способ отменить предыдущие шаги в серии шагов - PullRequest
0 голосов
/ 31 января 2019

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

try:
    A = createA()
except:
    return None

try:
    B = createB(A)
except:
    deleteA(A)
    return None

try:
    C = createC(B)
except:
    deleteB(B)
    deleteA(A)
    return None

try:
    D = createD(C)
except:
    deleteC(C)
    deleteB(B)
    deleteA(A)
    return None

return D

Я бы предпочел не повторяться, если это возможно.Как я могу улучшить это?Есть ли известный шаблон для подражания?

Одна вещь, которую я рассмотрел, это добавление deleteB() к deleteC() и deleteA() к deleteB().Это лучший способ сделать это?

Ответы [ 4 ]

0 голосов
/ 31 января 2019

То, что вы ищете, называется образец сувенира .Это один из шаблонов проектирования GoF:

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

Один из способов, как это можно реализовать с помощью python, можно найти здесь .

0 голосов
/ 31 января 2019

Как отмечается в комментариях, для этого и нужен протокол менеджера контекста.Однако, если вы еще не хотите углубляться в довольно продвинутую функцию, вы можете определить lambda анонимные функции по мере необходимости, чтобы запомнить, что нужно убрать ...

try:
    deleters = []
    A = createA()
    deleters.append( lambda: deleteA(A) )
    B = createB( A)
    deleters.append( lambda: deleteB(B) )
    C = createC( B)
    deleters.append( lambda: deleteC(C) )
    D = createD( C)
    return D
except:
    for d in reversed( deleters):
        d()
    return None
0 голосов
/ 31 января 2019

Это зависит от того, что именно означает «отменить».Например, если A, B, C, D и т. Д. Являются произвольными пользовательскими командами и их может быть много в любом порядке, то, скорее всего, вам нужно написать какую-то абстракцию вокруг do / undo.

Если в качестве альтернативы A, B, C, D и т. Д. Представляют собой ресурсы, которые необходимо привести в порядок (соединения с базой данных, файлы и т. Д.), То контекстные менеджеры могут быть более подходящими.

Или, возможно, A, B, CD - это совсем другое.

Небольшой фрагмент кода с использованием менеджеров контекста:

class A:
    def __enter__(self):
        set things up
        return thing
    def __exit__(self, type, value, traceback):
        tear things down

class B, C and D are similar

def doSomethingThatNeedsToUseD():
    try:
        with A() as a:
        with B() as b:
        with C() as c:
        with D() as d:
            d.doSomething()
    except:
        print("error")
0 голосов
/ 31 января 2019

Если вы просматриваете некоторые шаблоны проектирования, проверьте следующее:

Шаблон команды

Это, вероятно, то, что вы ищете.Кроме того, команды могут иметь действие «отменить».Проверьте также следующий вопрос, если он содержит аналогичную проблему, которая у вас есть. лучший шаблон дизайна для функции отмены

...