Newsgroup: it.comp.lang.c++
Titolo: Classi "cooperative"

Salve a tutti,
ho una classe con un bel po' di variabili e funzioni private, che
potrei spezzare in 3 sezioni *quasi* indipendenti.
Cioe', da:
class MyClass {
...
private:
  [tanta roba]
}
a
class MyClass {
...
private:
  ClassA a;
  ClassB b;
  ClassC c;
}
dove a, b, c racchiudono tutti i dati e funzioni originari. Non mi
serve per funzionalita' (anzi), ma per fare un po' di ordine nel
codice.
Pero', i tre oggetti non sono completamente indipendenti: ci sono
pochi casi in cui le classi dovrebbero accedere l'una a dei dati
dell'altra. Ad esempio, una funzione membro di 'a' dovrebbe accedere a
dei dati di 'b', una di 'b' a dei dati dei 'a', e una di 'c' a dei
dati di 'a' (sono solo tre funzioni, tre casi particolari). Non mi
pare di poterlo fare "friend", perche' ad es. la funzione di 'a' che
accede ai dati di 'b' e' chiamata all'interno di 'a' stesso... come fa
a sapere chi e' 'b' ?
Quindi:
1. Si puo' fare?
2. Se si, ha senso farlo? O e' un sintomo che c'e' qualcosa di
sbagliato nel design della classe?
Thx,
Pleg

 sbagliato nel design della classe?
A mio avviso c'è qualcosa di sbagliato nel design della classe.
Se c'è un coupling così forte tra componenti, o non vale la pena di
spezzare la funzionalità (almeno, non così come stai facendo tu), o si
possono usare classi annidate private, o c'è un'altra soluzione, per
esempio usando il pattern di delegazione.
Per poterti meglio aiutare, servirebbero però più dettagli, come
l'header delle unità di compilazione coinvolte.
Matteo

 o si possono usare classi annidate private,
...che è quello che stai già provando a fare. Evidentemente non è una
soluzione ottimale nel tuo caso, se hai incontrato problemi, per cui
barrerei quest'opzione.
Matteo

 l'header delle unità di compilazione coinvolte.
Ciao, grazie della risposta.
Immaginavo non fosse la cosa giusta da fare, ma mi sembrava una cosa
comoda. Cmq, qualche dettaglio in piu':
la classe gestisce un protocollo di comunicazione; da un lato riceve
messaggi dall'applicazione (diretti agli utenti), li spezzetta in
pacchetti e ne gestisce l'invio alla seriale; dall'altro, riceve
pacchetti dalla seriale, e li riassembla in messaggi che passa
all'applicazione.
Ci sono 3 insiemi di dati e funzioni *quasi* indipendenti:
1. le informazioni sugli utenti
2. il buffer d'invio
3. il buffer di ricezione
Ad esempio, il buffer di ricezione ha svariate decine di strutture e
funzioni di supporto. La classe principale "protocollo" non ha bisogno
di sapere nulla di queste strutture e funzioni, sarebbe molto piu'
semplice e strutturato avere una sottoclasse "BufferRicezione":
class Protocollo {
private:
    class BufferRicezione bufferRicezione;
}
Protocollo riceve un pacchetto, lo da' a BufferRicezione, e ne estrae
un messaggio completo. E tutto il funzionamento del buffer di
ricezione e' incapsulato nella classe ononima.
Pero': una delle funzioni di BufferRicezione (una su qualche decina)
deve leggere e aggiornare un campo che mi sarebbe invece comodo
incapsulare in "StatoUtenti" (sottoclasse "class StatoUtenti
statoUtenti;").
Quindi, non so bene come fare. Per ora semplicemente non ci sono
sottoclassi, tutti i dati e tutte le funzioni sono private di
Protocollo.
Mi piacerebbe fare quel lavoro di incapsulazione (mi renderebbe il
codice parecchio piu' leggibile e gestibile), ma ho il problema di cui
sopra.
Pleg

 sopra.
Anche se non sono certo di avere tutti i dettagli necessari, provo ad
esprimermi.
Se io avessi da modellare una comunicazione tra due buffer, userei il
pattern observer.
Quando, facendo polling o rimanendo in listening su una porta, la
classe in ricezione si accorge che ci sono dati, li elabora e
costruisce una struttura dati ad hoc che rappresenta un "pacchetto" o
comunque un messaggio.
Dopodiché avvisa l'observer che ha finito di preparare il tutto,
notificandolo e inviandogli la struttura dati che ha costruito (un
Message). A quel punto, l'observer (la classe che gestisce l'invio)
prepara il suo messaggio e lo manda alla seriale.
Quindi in realtà io non avrei una vera e propria classe "protocollo",
"bufferricezione" o "bufferinvio", quanto una classe "Receiver <
Observable" e una classe "Sender < Observer". Una terza classe,
"Message", conterrebbe tutti i membri dati e le funzioni per settarli
o recuperarli.
D'altro canto, se Sender e Receiver non devono sapere nulla di come
Message sia implementato, la cosa migliore è usare una factory
delegando ad essa l'istanziazione della giusta struttura dati a
partire da un Message generico. Se hai presente come è implementato lo
standard TCP/IP, è agnostico rispetto ai dati contenuti, che sono
delegati all'interpretazione dell'applicazione finale (per esempio,
una pagina HTML via HTTP da parte di un browser, etc.; ma via HTTP
possono essere spediti anche altri tipi di file, e quindi abbiamo un
ulteriore strato di astrazione, e così via).
Chiaramente si può complicare ancora la cosa per renderla più
flessibile e diminuire il coupling. Una possibilità collegata è il
pattern Mediator.
Se non vuoi che la struttura dati finale abbia un metodo di
serializzazione o deserializzazione, per esempio, potresti usare un
Visitor, che è un'ottima scelta e può essere costruito via una factory
separata.
Tuttavia, con così poche informazioni, faccio fatica ad essere più
preciso. Penso che tu debba chiederti se stai facendo "le classi
giuste", nel senso proprio di decidere cosa effettivamente astrarre e
rappresentare.
Ti consiglio comunque fortemente di leggere il libro "Design
Patterns".
http://www.play.com/Books/Books/4-/253395/Design-Patterns/Product.html
Ne esiste una versione in paperback anche in italiano, che è
decisamente meno costosa.
Ciao,
Matteo

 rappresentare.
Grazie del lungo post! lo rileggero' con calma.
Il problema, piu' che altro, e' che tutto questo va un po' oltre le
mie capacita' di programmazione (sono solo un "amateur"), e che
purtroppo devo farlo io lo stesso (non posso delegare :)
Quindi il codice che scrivo e' un po' un papocchione, e devo
rassegnarmici.
Avevo gia' sentito parlare dei "pattern", spero un giorno di avere
tempo di studiarli un po', cosi' potro' riorganizzare tutto il mio
codice.
Pleg