OO Design quando si utilizza la comunicazione

0

Ho 2 applicazioni una è scritta in C ++ e una è scritta in Java. le applicazioni comunicano passando array di byte che rappresentano un oggetto serializzato.

ogni oggetto di comunicazione rappresenta un comando e contiene l'id del comando e i dati associati.

Userò un esempio per descrivere il mio problema. Diciamo che ho 3 componenti. uno è responsabile della memorizzazione dei dati e del file system, uno è responsabile della presentazione dell'interfaccia utente e uno è responsabile della sicurezza e dell'autorizzazione degli utenti.

Un modo per accedere a un componente specifico consiste nell'avere un punto di accesso che eseguirà un caso di commutazione su tutti i possibili ID di comando.

pseudo:

    switch(commandId)
{
case SAVE_FILE:
DATASTORAGE::Save();
break;
case LOAD_FILE:
 DATASTORAGE::Load();
 break;
case AUTHORIZE:
 SECURITY_CONTROLLER::authorize();
 break;
case DENY_ACCESS:
 SECURITY_CONTROLLER::denyAccess();
 ...
}

In questo caso, se ho bisogno di cambiare il controller di sicurezza, ho bisogno di cambiare questo punto di ingresso principale.

così invece ho aggiunto un campo extra all'oggetto di comunicazione, che contiene l'id del componente che deve elaborare il comando. In questo caso, se desidero preformare l'autorizzazione, farò quanto segue:

communicationObject.commandId = AUTHORIZE;
communicationObject.target = SECURITY_CONTROLLER_ID;

E il main cambierà caso sugli obiettivi possibili e passerà l'id del comando al componente specfic che è responsabile di quel comando.

   switch(target)
{
case SECURITY_CONTROLLER_ID:
SECURITY_CONTROLLER::Process(commandId);
break;
case DATASTORAGE_ID:
 DATASTORAGE::Process(commandId);

 ...
}

Inoltre non mi piace questo nuovo design poiché richiede che il mittente conosca la struttura interna del ricevitore.

d'altra parte, se avessi accesso diretto alle altre classi dell'applicazione (non usando byte [] per le comunicazioni), la seconda opzione verrà mappata su qualcosa come: SECURITY_CONTROLLER :: Authorize (); mentre la prima opzione sarà mappata a qualcosa come Main.AUTHORIZE (), che non è sicuramente la strada da percorrere!

qual è l'approccio migliore in questo caso?

    
posta user844541 03.04.2014 - 10:46
fonte

2 risposte

1

Poiché ciò che stai facendo è scrivere un protocollo binario personalizzato per l'esecuzione di RPC in più lingue, è logico disporre di ID separati per i componenti e i relativi comandi.

Ad esempio: un numero fisso di byte all'inizio della matrice di byte potrebbe essere usato per specificare il componente, mentre i seguenti byte (un altro numero fisso) rappresenterebbero il comando specifico del componente. Infine, tutti i restanti byte rappresentano i dati associati.

Il tuo interruttore di primo livello verrebbe utilizzato per trovare il componente per l'ID del componente. Se tutti i componenti hanno la stessa superclasse, puoi anche sostituirlo con una std :: map che assegna oggetti reali (componenti) a ID componente.

Ma ogni componente dovrebbe avere un passaggio per mappare gli ID di comando ai metodi attuali.

Si noti che, in questa soluzione, è possibile utilizzare lo stesso ID comando per rappresentare diverse operazioni, se non si trovano nello stesso componente. In questo modo, è meno probabile che occorrano troppi byte per la sezione ID comando dell'array di byte.

    
risposta data 03.04.2014 - 13:03
fonte
0

Il modo più modulare è di lasciare che ogni modulo ricevente si registri con il gestore di comandi principale per ricevere i comandi che può gestire.

Supponendo che ci sia al massimo un gestore per ogni comando, si otterrebbe qualcosa come questo (pseudo codice)

class MainCommandHandler
{
public:
    RegisterCommandHandler(CommandID, ICommandHandler*);
    ProcessCommand(Command cmd)
    {
        if (commandHandlers.contains(cmd.id))
        {
            // delegate to the registered handler for this command
            commandHandlers.get(cmd.id)->HandleCommand(cmd);
        }
        else
        {
            // handle unknown commands
        }
    }
private:
    map<CommandID, ICommandHandler*> commandHandlers;
};

class SECURITY_CONTROLLER : public ICommandHandler
{
    someMethodOrConstructor() {
        mainCommandHandler.RegisterCommandHandler(AUTHORIZE, this);
        //... more registrations
    }
    HandleCommand(Command cmd)
    {
        switch(cmd.id)
        {
        case AUTHORIZE: authorize(); break;
        //... other *registered* commands
    }
};

Hai ancora il caso di commutazione sull'ID del comando, ma ora è nei componenti che effettivamente gestiscono il comando. Se ci sono comandi aggiuntivi, questi componenti dovrebbero essere comunque modificati, quindi l'inconveniente principale del tuo caso # 1 non esiste più.

    
risposta data 03.04.2014 - 12:33
fonte

Leggi altre domande sui tag