Pergunta

Greetings, neste momento estou a refatoração um dos meus programas, e eu encontrei um problema interessante.

Eu tenho Transitions em um autômato. Transitions sempre tem uma start-estado e um estado final. Algumas transições têm um rótulo, que codifica uma determinada ação que deve ser realizada após a travessia. Nenhum rótulo significa nenhuma ação. Algumas transições têm uma condição que deve ser cumprida, a fim de atravessar esta condição, se não há nenhuma condição, a transição é basicamente um epsilon-transição em uma NFA e será percorrido sem consumir um símbolo de entrada.

Eu preciso as seguintes operações:

  • Verifique se a transição tem um rótulo
  • essa etiqueta
  • adicionar um rótulo para uma transição
  • Verifique se a transição tem uma condição
  • obter esta condição
  • cheque de igualdade

A julgar pelos primeiros cinco pontos, isso soa como um decorador clara, com uma transição de base e dois decoradores: Etiquetado e condição. No entanto, esta abordagem tem um problema: duas transições são considerados iguais se o seu start-estado e estado final são os mesmos, os rótulos em ambas as transições são iguais (ou não-existente) e ambas as condições são as mesmas (ou não existente) . Com um decorador, eu poderia ter duas transições etiquetados ( "foo", condicional ( "bar", Transição ( "baz", "Qux"))) e condicional ( "bar", identificado como ( "foo", Transição ( "baz ", 'Qux'))), que precisa de uma igualdade não-local, ou seja, os decoradores precisaria coletar todos os dados ea transição deve comparar esses dados coletados em um set-base:

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)

Esta é uma abordagem limpa? Estou faltando alguma coisa?

Estou principalmente confuso, porque eu posso resolver isso - com nomes de classe mais longos - usando herança múltipla cooperativa:

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

se comporta classe LabledConditionalTransition exatamente como esperado -. E não tendo nenhum código lá é atraente e eu não coisa MI é confuso neste tamanho

Claro, a terceira opção seria apenas martelo tudo em uma única classe de transição com um monte de em Has_label / has_transition.

Então ... Estou confuso. Estou esquecendo de algo? Cuja implementação fica melhor? Como você lida com casos semelhantes, ou seja, objetos que se parecem com um Decorator pode lidar com eles, mas, em seguida, um tal método não-local vem por aí?

Editar : Adicionado a ConditionalTransition classe. Basicamente, este comporta-se um bocado como o decorador, menos a ordem criada pela ordem de criação dos decoradores, os controlos de transição para início e fim de ser correta, os controlos LabeledTransition classe para rótulo sendo verificações corretas e ConditionalTransition para a condição de ser correto.

Foi útil?

Solução

Eu acho que é claro que ninguém realmente entende a sua pergunta. Eu sugiro colocá-lo em contexto e torná-lo mais curto. Como exemplo, aqui está uma possível implementação do padrão de estado em python, por favor, estudá-lo para ter uma idéia.

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

A saída deste Programa seria:

door is open
closing door
door is closed
opening door
door is open
door is open

Outras dicas

A partir do código que foi publicado, a única diferença entre Transição e Rotulado de Transição é o retorno do get_lable () e Has_label (). Caso em que você pode comprimir esses dois uma única classe que define um atributo label para Nenhum e

return self.label is not None

na função Has_label ().

Você pode postar o código para a classe ConditionalTransition? Eu acho que isso iria torná-lo mais claro.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top