Newsgroup: it.comp.lang.c++
Titolo: [semi OT] OO Design e interfacce

Salve a tutti,
forse sarò leggermente OT ma non sapevo dove altro postare alcuni dubbi 
che ho.
Sto sviluppando (ovviamente in c++) un editor di testo per uso interno 
alla società in cui lavoro.
Sto cercando di utilizzare il più possibile il concetto di interfaccia 
pura per astrarre i vari oggetti, cercare di riutilizzare alcuni oggetti 
   e più che altro cercare di slegare i dati dalla loro visualizzazione.
Ad esempio, le varie configurazioni che possono essere fatte sull'editor 
sono gestite attraverso un interfaccia simile a questa:
class DialogConfig;
class Config
{
	public:
		virtual std::string setValue( const std::string& key, const 
std::string& value ) = 0;
		virtual std::string getValue( const std::string& key ) const = 0;
		virtual DialogConfig* getDialog() = 0;
}
Le varie classi "concrete" ereditano questa interfaccia ed implementano 
i metodi, ad esempio:
class FontConfig : virtual public Config
{
	....
}
Ora arrivo alle domande :).
La prima noia che mi capita è che il compilatore (GCC) mi da dei warning 
nella classe astratta Config perchè non ho definito un distruttore 
virtuale ...per ovviare a ciò ho definito un distruttore vuoto: non si 
può ovviare a ciò? In teoria un interfaccia non dovrebbe avere ne 
costruttore ne distruttore (almeno così ho letto :)).
La seconda domanda è invece più teorica e riguarda il metogo getDialog 
nella classe Config.
Questo metodo fa in modo che ciascuna classe di configurazione 
restituisca e gestisca la dialog grafica per gestire i fare in modo che 
l'utente possa modificare i dati.
Secondo la vostra esperienza è più corretto, dal punto di vista logico, 
che ciascuna classe di configurazione restituisca la Dialog grafica 
(come faccio ora) o è più corretto che la classe Dialog
sia slegata e che magari accetti nel costruttore la classe Config di cui 
deve visualizzare i dati interni?
Spero di non avervi annoiato troppo :)
Grazie a tutti quelli che vorranno darmi un piccolo parere.
Ciao
Gian

 deve visualizzare i dati interni?
Senza dubbio la seconda che hai detto.
Ciao,
Nicola

 Nicola
Ciao, grazie ancora della risposta.
Gian

 deve visualizzare i dati interni?
Secondo me una classe destinata a memorizzare la configurazione, non
dovrebbe neanche sapere che esiste una finestra di dialogo.
Le tue classi costituiscono semplicemente il "model"; ci saranno altre
entità (classi?) che modelleranno il "view", ovvero le tue finestre di
dialogo e poi ci saranno altre classi che faranno da "controller",
ovvero, a partire da una classe DialogConfig, apriranno una finestra
DialogWindow, ecc...

 dato...sbaglio?
Sbagli.
Forse potrebbe essere come dici tu in teoria, ma nella pratica del C++ 
non e' cosi'.
Qualcosa in merito ti ha gia' spiegato Nicola; se mastichi l'Inglese, 
trovi un po' piu' di informazioni qui:
http://www.parashift.com/c++-faq-lite/virtual-functions.html#faq-20.7
Una "rule of thumb" ancora piu' semplice e', se usi GCC (non so altri 
compilatori), quella di dare ascolto al warning che hai visto e 
correggere di conseguenza.
Per chiarire meglio ti faccio un esempio:
class A {
  public:
   ~A() {} // Se non lo definisci, lo fara il compilatore implicitamente
};
class B:public A {
    int*i;
  public:
    B():i(new int[1000]) {}
    ~B() {delete []i;}
};
int main() {
   B*b=new B; //viene chiamato il costruttore di B, che alloca 1000 int
   delete b; //viene chiamato il distruttore di B, che dealloca gli int
   A*a=new B; //viene chiamato il costruttore di B, che alloca 1000 int
   delete a; //viene chiamato il distruttore di A, che non dealloca nulla!!!
}
Il problema si risolve proprio rendendo virtuale ~A.
In tal caso, nell'ultima riga sopra (delete a) viene chiamato il 
distruttore ~B.
  bye
	av.

     av.
Grazie mille,
ora è molto più chiaro.
Ciao
Gian

 ancora bene....
Prendiamo un analogia col mondo reale: in termini concreti
"configurare" significa scegliere quali componenti inserire in un
dispositivo che ammette diverse possibilita'. Quindi quello che cerchi
di fare associando all'oggetto l'interfaccia per configurarlo
corrisponderebbe a pretendere che il computer che hai comprato su
internet ti arrivi a casa con dentro l'omino che te l'ha assemblato.
Nota che quello che descrivi e' un approccio che ha una certa
popolarita'; resta il fatto che e' un'assurdita' logica. Senza contare
che di solito l'interfaccia utente e' la parte di un'applicazione che
stenta di piu' a convergere verso una forma definitiva e lasciare che
questo destabilizzi anche gli elementi interni del sistema mi pare
poco sensato.
Ciao,
Nicola

 
In teoria è corretto, in pratica non so come realizzarlo...forse 
entriamo in OT ma ti spiego la mia situazione :
Analizzando solo le classi concrete immagina di avere una classe di 
configurazione dei font utilizzati, tipo:
class FontConfig
{
	...
	public std::string getFamily()
	{
		return editorDefault.family
	}	
	public int getSize()
	{
		return editorDefault.size;
	}
	private:
		Font editorDefault;		
}
Questo è la mia class model; gestisce il font utilizzato, lo estrae 
dalla configurazione e lo salva se viene cambiato dall'utente.
Poi ho la classe DialogFont che si occupa di permettere all'utente di 
gestire il cambio del font:
class DialogFont
{
	....
 
	private:
		std::string fontFamily;
		int fontSize;
 
}
se ho capito bene il tuo suggerimento dovrei avere una classe manager tipo:
class ConfigManager
{
	....
	public:
		void editApplicationFont()
		{
			DialogFont dlg;
			dlg.fontFamily = font.getFamily();
			dlg.fontSize = font.getSize();
			dlg.show();
			// Se l'utente clicca ok salvo eventuali modifiche, etc. etc.
		}
 
	private:
		FontConfig font;
}
Ho capito bene o sto completamente sgarrando l'analisi del problema?
Grazie mille
Ciao
Gian


Ciao,
grazie ancora dei preziosi spunti.
Gian

calimero wrote:
[...]
Opsss...scusate degli errori di ortografia e di battitura
Ciao
Gian