PDA

Visualizza la versione completa : [c++]Problema derivazione e design


giuseppe500
28-04-2010, 13:15
Ciao.
ho un array di stringhe che descrive il le caratteristiche di vari oggetti, uno per stringa:la posizione x,y e z e in particolare un parametro int nType che puo essere 0 o 1.

Pensavo di creare una classe base per tutti questi oggetti(che sono dei marker di augmented reality)di nome CBaseMarker e di gestire la creazione / cancellazione di questi marker tramite un parsing dell' array di stringhe che mi arriva un tot di volte al sec.
ogni stringa dell' array descrive le caratteristiche della classe del marker.

quindi so se c'è da rimuovere / aggiungere o modificare un marker tramite un ID che mi ritrovo sempre nella stringa n dell array di stringhe.

fino qui nessun problema.
Il problema nasce nell analisi :

I marker possono servire a visualizzare un immagine nella loro coordinata x,y,z o possono servire ad altre funzioni ad esempio una serie di marker con nType= 1 vanno uniti con una linea al fine di creare un "muro" un perimetro ma potranno servire anche ad altri scopi in futuro.

Per questo ho cercato di creare due classi derivanti da cBaseMarker CMArkerMesh(che visualizza un oggetto) e CMarkerWall (che serve per creare il perimetro inseme agli altri marker dello stesso tipo)
Poi volevo inserire tutti questi oggetti , sia MarkerMesh che MarkerWall in un container stl di tipo CBaseMarker.

ogni tot di tempo(quando mi arriva l'array di stringhe aggiornato) per visualizzare le mesh delle classi cmarkermesh basta scorrere il container e richiamare la funzione drawMesh di ogni oggetto.

E' proprio qui il problema di analisi:

1)è corretto creare dei metodi virtuali nella classe base che vengono utilizzati solo da un tipo di classe e non da altri tipi della stessa gerarchia di derivazione?
secondo me no , non ho capito bene quindi come fare
Per es:

2)Se l'oggetto è un MArkerWall quando invoco la funzione DrawMesh non fa un bel niente(o meglio viene invocata la funzione della classe base), perchè non reimplementa il metodo virtuale della classe base cbasemarker::DrawMesh
e questo è corretto(il fatto che non faccia un bel niente)?

Inoltre un altra domanda:
per calcolare il perimetro degli oggetti MarkerWall dovrei iterare il container e farmi ritornare , se l'oggetto è un MarkerWall il punto xyz da utilizzare poi successivamente dall' algoritmo che calcola il perimetro , ma solo se è un markerWall.

insomma ho questa incertezza , spero che persone piu' esperte di me e quindi piu capaci di capire che me di scrivere rispondano.

ps.
Con i template forse si riuscirebbe a migliorare il design secondo me ma prima aspetto una risposta alle domande.


Grazie

giuseppe500
28-04-2010, 21:50
Ps.
Intanto che ci siamo aggiungo il mio problema chiave di design oop:
quando cerco di diminuire la complessità di un problema cerco di inserire una nuova classe, e questo penso sia giusto.
Il problema è che la mia visione di questo sistema è sbagliato:
ogni volta creo una nuova classe che fa qualcosa d'altro , poi creo un puntatore al tipo di questa classe e lo incapsulo per creare una specie di superclasse che fa tutto , e questo secondo me è sbagliato, perchè i problemi sono sempre alla fine nella stessa classe , solo un livello piu su , ma non un livello di astrazione piu su , un livello di posizione , il che non vale niente.
ciao

shodan
28-04-2010, 23:53
1)è corretto creare dei metodi virtuali nella classe base che vengono utilizzati solo da un tipo di classe e non da altri tipi della stessa gerarchia di derivazione?

Si. Un esempio è la gerarchia di derivazione delle classi del DOM XML. Se noti, alcune classi hanno dei metodi derivati da Node, documentati come inutili su quel particolare tipo derivato e utili su altri.


Inoltre un altra domanda:
per calcolare il perimetro degli oggetti MarkerWall dovrei iterare il container e farmi ritornare , se l'oggetto è un MarkerWall il punto xyz da utilizzare poi successivamente dall' algoritmo che calcola il perimetro , ma solo se è un markerWall.


Detto quanto sopra, se il tuo oggetto reale è un MarkerWall, la funzione ritornerà qualcosa di valido; se non lo è falle ritornare qualcosa di non valido o lancia un'eccezione.
Se lavori con interfacce (puramente o parzialmente astratte), non deve interessarti (salvo casi particolari) cosa c'è sotto il cofano.

Andrea Simonassi
29-04-2010, 09:13
secondo me è una brutta pratica inserire nella classe base metodi usati solo da alcune classi derivate, non è un errore, io stesso lo faccio talvolta se mi sembra che sia più pratico. Le cose belle sono belle ma non sempre pratiche, la domanda da porsi in fase di progetto è : se aggiungessi un altro sottotipo tutti i mie algoritmi continueranno a funzionare senza dovere essere modificati? Se si allora qualcosa non va, altrimenti è tutto ok anche se non bello, alla fine dobbiamo produrre per guadagnare e portare a casa il pane, non fare arte.

In generale ogni volta che nel tuo codice aggiungi un IF per qualche tipo vuol dire che c'è rischio di spaghettizzazione del codice, con conseguente necessità di ORE di lavoro per ogni minima modifica e quindi perderci il guadagno prefissato... per questo bisogna cercare di limitare al massimo l'uso di IF (di questo genere)... senza però diventare paranoici.

Nel tuo caso mi pare che il principale errore (se così si può definire) sia che confondi la struttura logica del programma con la struttura dei dati in input, oppure che fai derivare la struttura del programma dalla struttura dei dati.

In realtà, la fase di input (parsing/deserializing, chiamiamola come vuoi) è quella in cui vengono istanziati gli oggetti ed è l'unica che deve essere consapevole (facendo degli IF) di che cosa istanziare sulla base del formato della stringa in input, per cui se mai dovessi aggiungere un nuovo sottotipo, l'unico IF aggiuntivo andrà inserito nel parser di input. (In output un metodo Serialize(stream * out) ti eviterà di usare un IF aggiuntivo)

Venendo al dunque, suppongo di avere un oggetto di interfaccia grafica che usa dei dati che leggi dall'input. Suppongo che se un determinato tag = 1 si tratti di un triangolo, se tag=0 si tratti di altri dati, sui triangoli voglio potere calcolare l'area su tutto voglio potere stampare la lista dei nomi degli oggetti.

un caso del genere potrebbe essere impementato cosi


class oggetto_base
{
virtual string nome() = 0;
string Serialize();
}

classe geometria_base : oggetto_base
{
virtual float area();
}

classe A:oggetto_base
{...}

classe triangolo:geometria_base{}


class graphic_interface
{
oggetto_base * oggetti;
geometria_base * oggetti_geometrici;
parser(inputstream)
{
se nType=1 {
istanzio un oggetto di tipo triangolo,
lo inserisco nella lista degli oggetti geometrici
lo inserisco nella lista degli oggetti
}
se ntype=0
{
allora istanzio un oggetto di tipo standard
lo inserisco nella lista degli oggetti
}
}

float calcolaPerimetro()
{
per ogni elemento in oggetti_geometrici
area += elemento->Area();
}
void stampalista()
{
per ogni elemento in oggetti
cout << oggetto->Nome();
}

}


se domani vuoi aggiungere il tipo RETTANGOLO, devi solo modificare PARSE e basta.

Loading