Привет, в настоящее время я занимаюсь рефакторингом одной из своих программ и обнаружил интересную проблему.
У меня есть переходы в автоматах. Переходы всегда имеют начальное и конечное состояние. Некоторые переходы имеют метку, которая кодирует определенное действие, которое должно быть выполнено при обходе. Отсутствие ярлыка означает отсутствие действий. Некоторые переходы имеют условие, которое должно быть выполнено для того, чтобы пройти это условие. Если условия отсутствуют, этот переход в основном является эпсилон-переходом в NFA и будет проходить без использования входного символа.
Мне нужны следующие операции:
- проверить, есть ли у перехода метка
- получить этот ярлык
- добавить метку к переходу
- проверить, есть ли у перехода условие
- получить это условие
- проверка на равенство
Судя по первым пяти пунктам, это звучит как чистый декоратор с базовым переходом и двумя декораторами: Labeled и Condition. Однако у этого подхода есть проблема: два перехода считаются равными, если их начальное состояние и конечное состояние одинаковы, метки на обоих переходах равны (или не существуют), и оба условия одинаковы (или не существуют) , С помощью декоратора у меня может быть два перехода с метками ("foo", Conditional ("bar", Transition ("baz", "qux"))) и Conditional ("bar", Labeled ("foo", Transition ("baz") "," qux "))), которым необходимо нелокальное равенство, то есть декораторам необходимо собрать все данные, а переход должен сравнить эти собранные данные на основе набора:
class Transition(object):
def __init__(self, start, end):
self.start = start
self.end = end
def get_label(self):
return None
def has_label(self):
return False
def collect_decorations(self, decorations):
return decorations
def internal_equality(self, my_decorations, other):
try:
return (self.start == other.start
and self.end == other.end
and my_decorations = other.collect_decorations())
def __eq__(self, other):
return self.internal_equality(self.collect_decorations({}), other)
class Labeled(object):
def __init__(self, label, base):
self.base = base
self.label = label
def has_label(self):
return True
def get_label(self):
return self.label
def collect_decorations(self, decorations):
assert 'label' not in decorations
decorations['label'] = self.label
return self.base.collect_decorations(decorations)
def __getattr__(self, attribute):
return self.base.__getattr(attribute)
Это чистый подход? Я что-то упустил?
Я в основном растерялся, потому что я могу решить эту проблему - с более длинными именами классов - используя кооперативное множественное наследование:
class Transition(object):
def __init__(self, **kwargs):
# init is pythons MI-madness ;-)
super(Transition, self).__init__(**kwargs)
self.start = kwargs['start']
self.end = kwargs['end']
def get_label(self):
return None
def get_condition(self):
return None
def __eq__(self, other):
try:
return self.start == other.start and self.end == other.end
except AttributeError:
return False
class LabeledTransition(Transition):
def __init__(self, **kwargs):
super(LabeledTransition).__init__(**kwargs)
self.label = kwargs['label']
def get_label(self):
return self.label
def __eq__(self):
super_result = super(LabeledTransition, self).__eq__(other)
try:
return super_result and self.label == other.label
except AttributeError:
return False
class ConditionalTransition(Transition):
def __init__(self, **kwargs):
super(ConditionalTransition, self).__init__(**kwargs)
self.condition = kwargs['condition']
def get_condition(self):
return self.condition
def __eq__(self, other):
super_result = super(ConditionalTransition, self).__eq__(other)
try:
return super_result and self.condition = other.condition
except AttributeError:
return False
# ConditionalTransition about the same, with get_condition
class LabeledConditionalTransition(LabeledTransition, ConditionalTransition):
pass
класс LabledConditionalTransition ведет себя точно так, как ожидалось - и отсутствие кода там привлекательно, и я не думаю, что MI смущает при таком размере.
Конечно, третьим вариантом было бы просто вбить все в один класс перехода с кучей в has_label / has_transition.
Итак ... я в замешательстве. Я что-то пропустил? Какая реализация выглядит лучше? Как вы справляетесь с подобными случаями, то есть объекты, которые выглядят как декоратор, могут обрабатывать их, но тогда такой нелокальный метод найдется?
EDIT :
Добавлен ConditionalTransition-класс. По сути, этот вид ведет себя как декоратор, за исключением порядка, созданного порядком создания декораторов, переходы проверяют правильность начала и конца, класс LabeledTransition проверяет правильность метки и проверяет ConditionalTransition условие правильное.