Come gestire una dichiarazione switch di grandi dimensioni con diversi comandi diversi?

3

Ho ricevuto il compito di refactoring di un'applicazione console, che è costantemente in esecuzione su un server e riceve messaggi da un bus di servizio.

In questo momento, analizza solo il messaggio in arrivo e, in base a una proprietà, userà un'istruzione switch per chiamare una delle molte diverse funzioni (circa 70 al momento, sempre in crescita). Un problema è che se una funzione fallisce, non viene ritentata. Per non parlare solo della bruttezza di una gigantesca dichiarazione dell'interruttore.

Sono propenso ad usare il Command Pattern per correggere questo ( link ), ma ho anche considerato un modello pub / sub per gestire queste funzioni.

Qualcuno sa quale potrebbe essere il miglior modello di architettura per questa situazione?

    
posta Steven 31.01.2018 - 22:09
fonte

3 risposte

2

Poiché hai codificato questa domanda con C# , offrirò la risposta specifica della tua domanda. C # e BCL offrono una versione integrata del pattern di comando: un dizionario di delegati. Piuttosto che avere, ad esempio:

SomeType Foo(MessageType message)
{
    switch (message.Id)
    {
        case "Id1" : return HandleId1();
        case "Id2" : return HandleId2();
        ...
    }
}

Lo sostituisci con

private readonly Dictionary<string, Func<SomeType>> _handlers =
    new Dictionary<string, Func<SomeType>>
    {
        ["Id1"] = HandleId1,
        ["Id2"] = HandleId2,
        ...
    };

...

SomeType Foo(MessageType message) => _handlers[message.Id]();
    
risposta data 01.02.2018 - 12:24
fonte
1

Dato che stai già utilizzando un bus di servizio, dividere l'app in molte app e la coda dei messaggi in una coda per tipo.

In questo modo la tua app gestisce solo un tipo di messaggio, permettendoti di ridimensionarli separatamente e aggiungere nuovi tipi senza ridistribuire.

È possibile utilizzare le code di errore del bus di servizio per riprovare i messaggi non riusciti

    
risposta data 04.02.2018 - 09:58
fonte
1

La risposta data da @ David Arno è ciò che vorrei fare, con una differenza. Non userei i delegati, ma preferirei usare gli oggetti Command. Quindi, avresti qualcosa di simile a questo:

Dictionary<string, ICommand> _handlers = new Dictionary<string, ICommand>();

dove

public interface ICommand
{
    void Execute();
}

Quindi, potresti implementare un oggetto nullo come questo:

public NullCommand : ICommand
{
    public void Execute()
    {
    }
}

e il tuo codice sarà simile a questo:

ICommand GetCommand(string id)
{
    ICommand retVal = null;
    if (!_handlers.TryGet(id, out retVal))
    {
        retVal = new NullCommand();
    }
    return retVal;
}

In questo modo, la proprietà è chiara e la testabilità è maggiore.

    
risposta data 05.04.2018 - 12:57
fonte

Leggi altre domande sui tag