PDA

View Full Version : [C++] Realizzare codice modulare


monelli
15-09-2009, 19:48
Ciao a tutti...

Devo realizzare un'applicazione in c++ per win32.

Questa applicazione dovrebbe essere formata da un main che permette di creare delle catene composte da vari blocchi.
Praticamente dal main posso lanciare su thread diversi catene e distruggerle.
Queste catene sono formate da diversi blocchi, il primo acquisisce dei dati, l'ultimo li visualizza e nel mezzo diversi blocchi che processano, i diversi blocchi sono autonomi e comunicano scambiandosi un char ad esempio.

Ogni blocco dovrebbe essere una classe, così sta su un file a parte, ci può lavorare un'altra persona e si puù modificare un blocco senza modificare l'intero programma.

Un esempio di catena potrebbe essere: blocco che acquisisce audio, blocco codifica, blocco decodifica, riproduzione audio...

Come posso realizzare una struttura del genere? Avete degli esempi? Suggerimenti?

_Claudio
15-09-2009, 20:28
Ciao a tutti...

Devo realizzare un'applicazione in c++ per win32.

Questa applicazione dovrebbe essere formata da un main che permette di creare delle catene composte da vari blocchi.
Praticamente dal main posso lanciare su thread diversi catene e distruggerle.
Queste catene sono formate da diversi blocchi, il primo acquisisce dei dati, l'ultimo li visualizza e nel mezzo diversi blocchi che processano, i diversi blocchi sono autonomi e comunicano scambiandosi un char ad esempio.

Ogni blocco dovrebbe essere una classe, così sta su un file a parte, ci può lavorare un'altra persona e si puù modificare un blocco senza modificare l'intero programma.

Un esempio di catena potrebbe essere: blocco che acquisisce audio, blocco codifica, blocco decodifica, riproduzione audio...

Come posso realizzare una struttura del genere? Avete degli esempi? Suggerimenti?

Non hai uno schema dell'applicazione che vuoi realizzare?
Se metti giù uno schema già ti viene più facile dividere i vari blocchi in classi.
L'unico consiglio che posso darti è di tenere divisa la logica applicativa con quella che interfaccia col SO (win32) che quindi realizza l'interfaccia e fa le chiamate a basso livello.

monelli
15-09-2009, 21:16
Ma più che i vari blocchi a me interessa proprio la struttura della catena... come farla???

Praticamente io nel main vorrei fare una cosa del genere:

Catena = new Chain();

Catena.aggancia(new BloccoA)
Catena.aggancia(new BloccoB)

Dove BloccoA e BloccoB sono classi che fanno cose completamnte diverse:

Ad esempio BloccoA acquisisce audio e BloccoB riproduce audio ma i due blocchi comunicano scambiandosi solo un char.....

Non sò se sono stato chiaro... così relizzo un loop audio... poi mam mano vado ad aggiungere blocchi che trattano l'audio

Y3PP4
15-09-2009, 23:24
Ma vuoi realizzare codice orientato agli oggetti o modulare?

Perchè parli di moduli, blocchi e classi e li usi tutti insieme nello stesso pensiero :s

Comunque, anche se realizzi una applicazione OOP non è detto che le varie classi siano mutabili a piacere. Riguardo l'autonomia, non dare per scontato che una classe sia liberamente modificabile, dato che in molti casi una modifica della classe richiede anche la revisione del suo utilizzo, specie se cambi i metodi della classe e hai un oggetto che cerca di chiamare i vecchi metodi, non più esistenti.

Comunque riguardo l'autonomia ti consiglio di leggere questo dettagliatissimo post (http://www.hwupgrade.it/forum/showpost.php?p=28808605&postcount=7) di PGI-Bis (mi prendo la libertà di linkartelo io :D).

Spiega molto bene questo concetto.
Fai chiarezza poi cosa vuoi ottenere, sfrutta il consiglio di _Claudio e fai uno schema logico dell'applicazione.
Che io sappia la "chained programming" non esiste tra i paradigmi di sviluppo.
Esistono invece altri paradigmi che ti permettono di creare un programma con quella logica. Comunque dagli esempi sembra tu voglia usare OOP, ma non credo sia fattibile quel che cerchi.

Non puoi passare una classe (e non un oggetto) e sperare che questa magicamente comunichi con il metodo. Idem per l'oggetto, in che modo intendi farli comunicare?

Non è solo dicendo: voglio fare
System.start();
System.run(Environment);

Che realizzo un sistema operativo :stordita:

PGI-Bis
16-09-2009, 08:07
Ma più che i vari blocchi a me interessa proprio la struttura della catena... come farla???

Praticamente io nel main vorrei fare una cosa del genere:

Catena = new Chain();

Catena.aggancia(new BloccoA)
Catena.aggancia(new BloccoB)

Dove BloccoA e BloccoB sono classi che fanno cose completamnte diverse:

Ad esempio BloccoA acquisisce audio e BloccoB riproduce audio ma i due blocchi comunicano scambiandosi solo un char.....

Non sò se sono stato chiaro... così relizzo un loop audio... poi mam mano vado ad aggiungere blocchi che trattano l'audio

In pseudo codice:

Blocco
-Catena catena
-string nome
+getNome()
+setCatena(Catena c)
+getCatena()
+ricevi(char)

Catena
-mappa string-blocco
+aggancia(Blocco b) = mappa.put(b.getNome(), b), b.setCatena(this)
+getBlocco(String nome) = mappa.get(nome)

Una volta inseriti nella catena i blocchi (sottotipi di Blocco) comunicano tra loro attraverso la condivisione della stessa catena.

Il possesso di un nome da parte dei blocchi non è strettamente necessario. Dipende dal protocollo di comunicazione. Ad esempio se non ti interessa che un blocco X comunichi specificamente con un blocco Y puoi dire:

Blocco
-Catena catena
+setCatena(Catena c)
+getCatena()
+ricevi(char)

Catena
-lista di blocchi
+aggancia(Blocco b) = lista += b, b.setCatena(this)
+comunica(char c) = per ogni blocco b in lista blocchi, b.ricevi(c)

monelli
16-09-2009, 09:00
In pseudo codice:

Questo si avvicina molto a quello che vorrei fare... Però il discorso è che i vari blocchi della catena sono sempre in esecuzione e si scambiano messaggi (char) sempre nello stesso verso.

Catena

BloccoA----BloccoB----BloccoC

BloccoA invia sempre messaggi a BloccoB
BloccoB invia sempre messaggi a BloccoC

Scusate è che non sò spiegare bene quello che voglio fare... provo a essere più chiaro...

Io in pratica creo un oggetto BloccoA, uno BloccoB, uno BloccoC

BloccoA acquisisce audio e lo manda sotto forma di messaggi char al blocco successivo

BloccoB riceve questo char fa delle modifiche e invia il char al blocco successivo

BloccoC riceve il char e riproduce l'audio


Anche eliminando il bloccoB dalla catena il tutto funziona... e potrei inserire un numero diverso di blocchiB

PGI-Bis
16-09-2009, 09:09
Ti basterà dire:

Catena
+comunica(char c, Blocco sender) =
prendi il nodo x che viene dopo sender nella
lista dei nodi e, se c'è, x.ricevi(c)

_Claudio
16-09-2009, 10:56
Se i blocchi sono sempre in ESECUZIONE CONTEMPORANEAMENTE allora più che delle classi devi usare dei thread con pipe. Su cui puoi dinamicamente caricare l'esecuzione di un blocco (processo) sui thread e gestire le varie pipe.

Nulla di complicato, ci metti più a dirlo che a farlo.

Tommo
16-09-2009, 11:39
Cmq ricevere e passare char è decisamente riduttivo, forse sarebbe meglio passare una classe Message o roba del genere? :stordita:

PGI-Bis
16-09-2009, 11:48
Se i blocchi sono sempre in ESECUZIONE CONTEMPORANEAMENTE allora più che delle classi devi usare dei thread con pipe. Su cui puoi dinamicamente caricare l'esecuzione di un blocco (processo) sui thread e gestire le varie pipe.

Nulla di complicato, ci metti più a dirlo che a farlo.

Così però perde la manifestazione della struttura che vuole dare al suo programma affidandola ad una caratteristica implicita del concetto di flusso.

_Claudio
16-09-2009, 12:52
Così però perde la manifestazione della struttura che vuole dare al suo programma affidandola ad una caratteristica implicita del concetto di flusso.

Sinceramente non ho capito la struttura del programma :fagiano: , non c'è nemmeno una formalizzazione dello stesso (ecco l'utilità dei tanto vituperati diagrammi UML et similia).

Se i blocchi sono dinamici e in qualche modo devono elaborare dati real time contemporaneamente e scambiarsi char tra di loro, non c'è nulla di meglio che i thread.

marco.r
16-09-2009, 13:12
Ciao a tutti...

Devo realizzare un'applicazione in c++ per win32.

Questa applicazione dovrebbe essere formata da un main che permette di creare delle catene composte da vari blocchi.
Praticamente dal main posso lanciare su thread diversi catene e distruggerle.
Queste catene sono formate da diversi blocchi, il primo acquisisce dei dati, l'ultimo li visualizza e nel mezzo diversi blocchi che processano, i diversi blocchi sono autonomi e comunicano scambiandosi un char ad esempio.

Ogni blocco dovrebbe essere una classe, così sta su un file a parte, ci può lavorare un'altra persona e si puù modificare un blocco senza modificare l'intero programma.

Un esempio di catena potrebbe essere: blocco che acquisisce audio, blocco codifica, blocco decodifica, riproduzione audio...

Come posso realizzare una struttura del genere? Avete degli esempi? Suggerimenti?
[/quote]
I blocchi di una singola catena girano su thread diversi o lo stesso ?

banryu79
16-09-2009, 13:13
Se i blocchi sono dinamici e in qualche modo devono elaborare dati real time contemporaneamente e scambiarsi char tra di loro, non c'è nulla di meglio che i thread.
Da quel che ho capito (lettura del primo post di monelli) i Blocchi non sono dinamici: sono statici.
A lui serve poter "spezzare" una Catena in Blocchi (e quindi, viceversa, comporre una Catena dichiarando una sequenza di aggiunte ordinate di singoli Blocchi alla stessa) solo per poter affidare l'implementazione di un qualsiasi singolo Blocco a un singolo sviluppatore che non si deve preoccupare del "mondo esterno" al Blocco stesso su cui lavora.

Nel "mondo esterno" poi, i vari blocchi verranno istanziati e aggiunti in ordine a formare una Catena: esiste poi la possibilità, nel contesto dell'applicazione, di lanciare contemporaneamente più Catene in esecuzione: ognuna sul suo bel thread.

Infine, in ogni Catena il primo e l'ultimo Blocco della stessa sono sempre gli stessi: il primo è il Blocco che acquisisce l'audio in input alla Catena, l'ultimo il Blocco che ne esegue la riproduzione.

monelli
16-09-2009, 13:32
Da quel che ho capito

Ecco esatto ottime spiegazione... ciò è quello che vorrei realizzare... con la piccola differanza che il primo e l'ultimo blocco della sequenza non sono sempre gli stessi

marco.r
16-09-2009, 13:40
Ecco esatto ottime spiegazione... ciò è quello che vorrei realizzare... con la piccola differanza che il primo e l'ultimo blocco della sequenza non sono sempre gli stessi

se la catena gira in un singolo thread, e input/output sono sempre lo stesso tipo, diventa molto semplice

class Block
{
virtual void execute( char input ) =0;
virtual char output() =0;
};



E il loop (wrappato magari in una classe Chain ) diventa qualcosa tipo


std::vector< shared_ptr<Block> > chain;

...
chain[0]->execute( myInputChar );
for ( int i=1 ; i< chain.size(); ++i )
{
chain[i]->execute( chain[i-1]->output() );
}


Ovviamente varianti analoghe con altri tipi di contenitori sono possibili secondo necessita'.
Se i vari blocchi devono poter gestire tipi di input/output diversi la cosa diventa piu' complicata, ma non troppo difficile

banryu79
16-09-2009, 14:01
Se i vari blocchi devono poter gestire tipi di input/output diversi la cosa diventa piu' complicata, ma non troppo difficile
"Smells" like Decorator pattern :D

monelli
16-09-2009, 14:09
Tanto il blocco iniziale in qualsiasi modo prende l'input: audio, tastiera, rete ecc non fa altro che prenderlo e metterlo sulla catena uscendo come char... Tu invece nell'esempio presumi che al primo blocco arrivi già in input un char ma non è così.

Non si dovrebbe complicare troppo il tutto...

Adesso inizio a provare a fare un esempio banale:

Primo blocco genera una stringa "Hello" secondo blocco inverte la stringa terzo blocco stampa a video... "olleH"

Inserendo nella catena due volte il secondo blocco la stringa dovrebbe uscire "Hello"

marco.r
16-09-2009, 14:15
"Smells" like Decorator pattern :D

no in realta' io pensavo semplicemente ad una cosa a template usando delle buone vecchie liste.



template <typename Input, typename Output>
class Block
{
public:
virtual void execute( const Input& input ) =0;
virtual const Output& output() = 0;
};


template <typename Input, typename Output,typename T>
class Chain : public Block<Input,Output>
{
public:
Chain( Block<Input,T>*, Block<T,Output>* );
void execute(const Input& input) { _first->execute(input); _second->execute( _first->output() ); }
const Output& output(){ return _second->output(); }
};

La catena la costruisci componendo pezzi singoli e poi le catene tra di loro. Paghi lo scotto che lo stack cresce pero' almeno mantieni la type safety.
La verbosita' del C++ non rende giustizia all'idea, che di per se' e' molto semplice.

marco.r
16-09-2009, 14:17
Tanto il blocco iniziale in qualsiasi modo prende l'input: audio, tastiera, rete ecc non fa altro che prenderlo e metterlo sulla catena uscendo come char... Tu invece nell'esempio presumi che al primo blocco arrivi già in input un char ma non è così.

Non si dovrebbe complicare troppo il tutto...

Adesso inizio a provare a fare un esempio banale:

Primo blocco genera una stringa "Hello" secondo blocco inverte la stringa terzo blocco stampa a video... "olleH"

Inserendo nella catena due volte il secondo blocco la stringa dovrebbe uscire "Hello"

Beh, la gestione del primo blocco uno la fa come vuole. Io gli ho dato un input arbitrario, si puo' ovviamente fare in modo diverso secondo necessita'.