Приветствую, сейчас занимаюсь рефакторингом одной из своих программ и обнаружил интересную проблему.
У меня есть переходы в автомате. У переходов всегда есть начальное и конечное состояние. Некоторые переходы имеют метку, которая кодирует определенное действие, которое должно быть выполнено при обходе. Нет ярлыка - нет действия. У некоторых переходов есть условие, которое должно быть выполнено, чтобы пройти это условие, если нет условия, переход в основном является эпсилон-переходом в NFA и будет пройден без использования входного символа.
Мне нужны следующие операции:
Судя по первым пяти пунктам, это звучит как чистый декоратор с базовым переходом и двумя декораторами: Labeled и Condition. Однако у этого подхода есть проблема: два перехода считаются равными, если их начальное и конечное состояние одинаковы, метки на обоих переходах равны (или не существуют) и оба условия одинаковы (или не существуют). . С помощью декоратора у меня может быть два перехода с пометкой («foo», «условный» («bar», «переход» («baz», «qux»))) и «условный» («bar», «помеченный» («foo», «переход» («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.
Итак ... я в замешательстве. Я что-то упускаю? Какая реализация выглядит лучше? Как вы справляетесь с подобными случаями, то есть объекты, которые выглядят как декоратор, могут справиться с ними, но затем появляется такой нелокальный метод?
РЕДАКТИРОВАТЬ: Добавлен класс ConditionalTransition. По сути, этот вид ведет себя как декоратор, за вычетом порядка, созданного порядком создания декораторов, переход проверяет правильность начала и конца, класс LabeledTransition проверяет правильность метки, а ConditionalTransition проверяет правильность условия.






Из опубликованного кода единственная разница между переходом и помеченным переходом - это возврат get_lable () и has_label (). В этом случае вы можете сжать эти два одного класса, который устанавливает для атрибута label значение None и
return self.label is not None
в функции has_label ().
Можете выложить код для класса ConditionalTransition? Думаю, это прояснит.
Думаю, ясно, что никто толком не понимает вашего вопроса. Я бы посоветовал поместить его в контекст и сделать его короче. В качестве примера, вот одна из возможных реализаций паттерна состояний в Python. Изучите ее, чтобы получить представление.
class State(object):
def __init__(self, name):
self.name = name
def __repr__(self):
return self.name
class Automaton(object):
def __init__(self, instance, start):
self._state = start
self.transitions = instance.transitions()
def get_state(self):
return self._state
def set_state(self, target):
transition = self.transitions.get((self.state, target))
if transition:
action, condition = transition
if condition:
if condition():
if action:
action()
self._state = target
else:
self._state = target
else:
self._state = target
state = property(get_state, set_state)
class Door(object):
open = State('open')
closed = State('closed')
def __init__(self, blocked=False):
self.blocked = blocked
def close(self):
print 'closing door'
def do_open(self):
print 'opening door'
def not_blocked(self):
return not self.blocked
def transitions(self):
return {
(self.open, self.closed):(self.close, self.not_blocked),
(self.closed, self.open):(self.do_open, self.not_blocked),
}
if __name__ == '__main__':
door = Door()
automaton = Automaton(door, door.open)
print 'door is', automaton.state
automaton.state = door.closed
print 'door is', automaton.state
automaton.state = door.open
print 'door is', automaton.state
door.blocked = True
automaton.state = door.closed
print 'door is', automaton.state
вывод этой программы будет:
door is open
closing door
door is closed
opening door
door is open
door is open
мне кажется, что вы пытаетесь написать Java-код на Python.