Come gestire strutture di tipo fabbrica con un'enorme quantità di classi?

0

Ho il problema che voglio essere in grado di catturare un set di messaggi SNMP, e alcuni di loro voglio analizzare per creare un'istanza di una classe definita dall'utente. Potrei ad esempio voler identificare se un messaggio SNMP è un messaggio TRAP, e se lo è voglio identificare il tipo di TRAP e creare un'istanza di questo tipo.

Esempio: Tipo di messaggio SNMP: TRAP: ALARM: MINOR_ALARM

In questo caso voglio istanziare una classe di tipo MinorAlarm, contenente le informazioni dell'allarme e alcune funzionalità ben definite da un'interfaccia (come stampare l'allarme, determinare quando è successo, ...)

Il numero di diversi tipi alla fine diventerà grande e deve essere semplice aggiungere anche nuovi tipi. L'attuale implementazione è molto limitata e disordinata. Fondamentalmente consiste in un'enorme istruzione if-else in cui solo un sottoinsieme dei tipi è supportato in questo momento.

Il nome del tipo SNMP specifico può essere ottenuto dal messaggio SNMP attraverso una stringa come "1.1.1.0.2.6.22.33" (i numeri sono completamente compilati).

Credo che uno schema di fabbrica potrebbe diventare troppo disordinato qui. L'ipotesi è che una sorta di tabella di ricerca funzionerebbe, ma se possibile vorrei evitare l'uso di Reflection (poiché sarà difficile da leggere e capire).

Un pensiero allentato sarebbe quello di utilizzare una sorta di fabbrica astratta con una struttura gerarchica. Questo sarebbe simile alla struttura gerarchica della struttura annidata dell'albero MIB. Questa potrebbe essere l'idea migliore, ma implicherà ancora lo scavare in un pasticcio di if-else o switch. Qualcuno ha qualche buona idea su come procedere?

    
posta patrik 03.05.2017 - 10:05
fonte

2 risposte

2

Cercherò di evitare l'istanziazione di nuove classi per messaggio.

Invece hai un tipo di messaggio generico e una raccolta di gestori specifici del tipo in un dizionario.

Dictionary<string, IHander> Handlers;

public void ReadMessage(Message m)
{
    var handler = Handlers[m.TypeName];
    if(handler == null) { handler = DefaultHandler;)
    handler.ReadMessage(m);
}

Ovviamente puoi fare la stessa cosa con un Dizionario delle Fabbriche, ma sebbene il modello di gestore sia più procedurale è più elegante. Non richiedendo di creare nuove istanze di classi diverse, chiama un singolo metodo e disponili immediatamente.

Inoltre, puoi immaginare il caso in cui una classe Message ha parametri di costruzione diversi dagli altri. Questo modello consente di creare un'istanza dei gestori una volta all'avvio, in cui è possibile specificare la costruzione di ciascuno individualmente. Piuttosto che nel ciclo di gestione dei messaggi in cui è necessario un parametro condizionale ed extra.

    
risposta data 03.05.2017 - 10:15
fonte
0

Aggiungi un metodo all'interfaccia della fabbrica astratta che controlla se una determinata stringa di messaggi corrisponde alla fabbrica. In questo modo puoi mettere la logica che decide quando utilizzare una fabbrica specifica nella fabbrica stessa e non è necessario creare un enorme albero if-else. Questo sarebbe simile a questo:

private List<AbstractMessageFactory> messageFactories = new ArrayList<>();

public void registerMessageFactory(AbstractMessageFactory factory) {
      messageFactories.add(factory);
}

public Message createMessageFromString(String messageString) {

    for (AbstractMessageFactory f: messageFactories) {
          if (f.matches(messageString) {
               return f.createMessage(messageString);
          }
    }

    throw new UnhandledMessageException(messageString);
}

Un esempio di una classe factory astratta:

public TrapMessageFactory implements AbstractMessageFactory {

     public matches(String messageString) {
         return messageString.contains("1.1.1.0.2.6.22.33");
     }

     public createMessage(String messageString) {
          return new TrapMessage(messageString);
     }
}

Ora potrebbe annidare fabbriche del genere con alcune fabbriche che fanno lo stesso e delegano alla propria lista di fabbriche di messaggi, che delegano anche e così via. Ciò potrebbe avere benefici in termini di prestazioni, poiché può ridurre alcuni confronti ridondanti. Ma vorrei comunque sconsigliarlo, perché ora non puoi più dire in quali condizioni verrà creato esattamente un determinato messaggio semplicemente guardando il matches -method di un singolo factory.

    
risposta data 03.05.2017 - 10:42
fonte

Leggi altre domande sui tag