Progettazione OOP per la coda di elaborazione degli eventi condizionali

4

Questo sarà in C ++ 11, ma la progettazione dell'oggetto dovrebbe essere piuttosto agnostica.

Ho 3 classi di interfaccia, IEvent , ICondition , IRunnable .

Il ciclo principale elabora più tipi di IEvent , che vanno da "un'applicazione lanciata" a "Posizione utente cliccata (x, y)". Quindi per ogni tipo di evento, una lista di ICondition viene notificata attraverso un'interfaccia listener. Ad esempio, ConditionUserClickedPos implementa IEventClickListener::onClick(int x, int y) , che viene chiamato dal ciclo principale.

Se la posizione è all'interno delle condizioni, uno o più oggetti IRunnable vengono richiamati tramite IRunnable::execute(IEvent triggeringEvent) , come class RunnableDrawCircleAtClickPosition e class RunnableShowPrettyWindow .

Il mio problema è il seguente:

Nell'implementazione IRunnable::execute(IEvent triggeringEvent) , ho bisogno di ottenere le informazioni precise dell'evento, ma non conosco la gerarchia di classi esatta dell'evento di trigger.

Questo può essere facilmente risolto con dynamic_cast, controllando i metodi typeid o altri metodi oop riflettenti, ma quelli di solito generano un codice piuttosto puzzolente. Sto anche cercando di mantenere il codice estendibile per eventi, condizioni e runnables nuovi e non correlati di cui ancora non so nulla.

Potrei anche dichiarare una serie di sovraccarichi per ::execute(...) in base ai tipi di classi per bambini, ma anche questo non sembra corretto.

C'è un proiettile d'argento che ho perso qui?

    
posta Eric 02.06.2015 - 01:06
fonte

1 risposta

1

Il mio suggerimento è scritto sotto in PHP pseudocodice. Quindi, abbiamo molti tipi di eventi, tutti implementando l'interfaccia IAbstractEvent. Quando abbiamo bisogno di elaborare un evento, diamo questo evento a un metodo factory FactoryConstructor::constructFactory() . Questo metodo crea per noi un factory astratto AbstractLoopProcessorFactory discendente per l'elaborazione degli eventi di questo particolare tipo.

Quando abbiamo un evento il cui nome è DrawCircle , il metodo factory crea DrawCircleLoopProcessorFactory per noi. Questo factory può creare% di% co_de concreto e% di% di co_de che può funzionare con l'evento DrawCirlceConditionProcessor .

L'interfaccia IDrawCircleEvent può avere un numero arbitrario di metodi e strutture arbitrarie. Solo dovrebbe estendere DrawCirlceRunnable per consentire al nostro stabilimento astratto di funzionare. Quindi, in DrawCirlceConditionProcessor sai già, che l'evento reale passato a te è IDrawCircleEvent e puoi fare riferimento come è.

Probabilmente è richiesto un cast di tipo perché devi essere in grado di lavorare uniformemente con una coda di eventi. Ma lo scambiate per la separazione logica.

interface IAbstractEvent
{
    public function getName();
}

interface IDrawCircleEvent extends IAbstractEvent
{

}

interface IAbstractConditionProcessor
{
    /**
     * @return bool
     */
    public function check(IAbstractEvent $event);
}

interface IDrawCircleConditionProcessor extends IAbstractConditionProcessor
{

}

interface IAbstractRunnable
{
    /**
     * @param IAbstractEvent $event
     *
     * @return void
     */
    public function process(IAbstractEvent $event);
}

interface IDrawCircleRunnable extends IAbstractRunnable
{

}

abstract class AbstractLoopProcessorFactory
{
    /**
     * @param IAbstractEvent $event
     *
     * @return IAbstractConditionProcessor
     */
    abstract function getConditionProcessor(IAbstractEvent $event);

    /**
     * @param IAbstractEvent $event
     *
     * @return IAbstractRunnable
     */
    abstract function getRunnable(IAbstractEvent $event);
}

class DrawCircleLoopProcessorFactory extends AbstractLoopProcessorFactory
{
    public function getConditionProcessor(IAbstractEvent $event)
    {
        return new DrawCirlceConditionProcessor($event);
    }

    public function getRunnable(IAbstractEvent $event)
    {
        return new DrawCirlceRunnable($event);
    }
}

class FactoryConstructor
{
    /**
     * @param IAbstractEvent $event
     *
     * @return AbstractLoopProcessorFactory
     * @throws Exception
     */
    public static function constructFactory(IAbstractEvent $event)
    {
        switch ($event->getName()) {
            case "DrawCircle":
                return new DrawCircleLoopProcessorFactory();
            default:
                throw new Exception("Unknown event name {$event->getName()}");
        }
    }
}

class Application
{
    public static function main()
    {
        /**
         * @var IAbstractEvent[]
         */
        $eventList = [];

        foreach ($eventList as $event) {
            $factory = FactoryConstructor::constructFactory($event);
            $conditionChecker = $factory->getConditionProcessor();
            if ($conditionChecker->check($event)) {
                $runnable = $factory->getRunnable($event);
                $runnable->process($event);
            }
        }

    }
}
    
risposta data 02.06.2015 - 18:02
fonte

Leggi altre domande sui tag