Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
Codificatore - Progressi verso l'1.1

Codificatore

Sommario | Admin | Forum | Bugs | Todo | Files

Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 14:47
Lunedì, 02/02/2015
La riorganizzazione del codice secondo le linee suggerite da marco_ e TheDarkJuster si sta dimostrando più intricata del previsto, per l'autodidatta che sono. "Isolare" parti di un programma non mi è così semplice come pensavo a prima vista. Scopro ogni momento d'aver bisogno di tanta, tanta pratica e di montagne di ripensamento del mio modo di intendere la realizzazione d'un programma anche semplice come il "Codificatore". Ma non demordo! :)


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Avatar
marco_ (Normal User)
Newbie


Messaggi: 2
Iscritto: 30/01/2015

Segnala al moderatore
Postato alle 16:24
Lunedì, 02/02/2015
Probabilmente il metodo migliore per iniziare è leggere qualche articolo scritto bene e/o qualche buon source, cercare di reinventare la ruota è faticoso(anche se non è un cattivo esercizio).

:ot:
<AldoBaldo> di poche parole, eh?
Se fossi rimasto altri 5 minuti ti avrei risposto. In genere di sera trovi più gente(non molta).

PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 16:41
Lunedì, 02/02/2015
Fino a qualche mese fa era ostico anche per me utilizzare le classi in modo logico, pensare a come utilizzarle era una faticaccia ma devo dire che dopo essermi costretto a non scrivere codice fuori da una classe, main escluso mi sono abitutato abbastanza in fretta, soprattutto al modo di vedere logicamente gli oggetti. L'unico consiglio che posso darti è pensa al tuo algoritmo come qualcosa di astratto: molto astratto, ma teoricamente implementabile ovunque. E guarda la STL del C++, perchè ti sprona un sacco a usare codice c++ organizzato in modo logico. O almeno, per me è così

PM Quote
Avatar
Roby94 (Member)
Guru


Messaggi: 1170
Iscritto: 28/12/2009

Segnala al moderatore
Postato alle 17:19
Lunedì, 02/02/2015
Non esistono regole fisse per la progettazione di un diagramma a classi, è un esercizio per lo piu di design. Se per un problema algoritmico ci sono 20 soluzioni, per lo stesso problema visto dal punto di design delle classi magari ce ne sono 200. Ci sono però delle linee guida che si possono seguire. Nel tuo caso hai un programma che codifica e decodifica un file quindi un punto comune è questo, un file, quindi per la classe avrai un puntatore ad a questo file, magari passato per costruttore; avrai anche un puntatore al file dizionario; stesso ragionamento. Avrai dei metodi pubblici che permettono la codifica e la decodifica del file, dei metodi che permettono di cambiare il file source, ugualmente delle funzioni che permettano il cambio del dizionario.
Dovresti applicare un interpretazione a strati

Applicazione con interfaccia utente
----------------------------------
Classe di codifica e decodifica
----------------------------------
File sorgente | file dizionario

Devi solo pensare un interfaccia facilmente fruibile dallo strato applicativo, la stratificazione ti costringe a mantenere le specifiche di interfaccia mentre aggiorni il contenuto della classe.
Cerca di capire cosa avrà bisogno l'applicazione per poter funzionare senza dover modificare in alcun modo la classe.

Certo che avere un po di esperienza in un linguaggio puramente OOP ti aiuterebbe non poco.

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 18:16
Lunedì, 02/02/2015
Grazie dei consigli, dei quali cerco di tenere sempre conto (in caso contrario perché dovrei star qui a stressarvi?).

Al momento credo d'essere a buon punto nell'implementare una classe cdf (CoDiFicatore) che viene creata "nulla", ovvero senza contenere dati di sorta, e successivamente foraggiata con una stringa che rappresenta la chiave e con il percorso d'un file ricavato tramite la classica finestra di navigazione dalla parte del programma che si occupa dell'interfaccia.

La classe...
1. ...crea un duplicato della stringa della chiave e la immagazzina in una delle sue proprietà private.
2. ...apre e legge il file del quale riceve il percorso, usando la libreria standard, caricandone il testo da codificare/decodificare.
3. ...riconosce e memorizza l'operazione da compiere (codifica o decodifica) in base all'estensione del file.
4. ... effettua la verifica della compatibilità tra i dati da elaborare e la chiave per elaborarli.
5. ... codifica/decodifica i dati salvandoli autonomamente in un file del quale compone il percorso a partire da quello del file "sorgente".

Fornisce inoltre alcuni metodi "accessori" di lettura per permettere alla sezione di interfaccia di conoscere lo stato delle proprietà e adeguare l'attivazione dei pulsanti, le stringhe di segnalazione per l'utente, la lista dei caratteri mancanti, ecc.

Nelle intenzioni dovrebbe avere ben pochi metodi pubblici, occupandosi "interiormente" degli aspetti più macchinosi dei procedimenti attivati dai comandi (a me sembra che una classe dovrebbe comportarsi così, ma ogni tanto le mie certezze vacillano).

Non credo che implementerò costruttori di copia e overload di operatori, perché non intendo creare situazioni che li richiedano. FORSE sottoporrò a overload le funzioni creatrici, per fare in modo che accettino all'atto della creazione i dati che ora devono essere forniti successivamente. Non dovrebbe essere complicato, perché nei fatti dovrebbe essere sufficiente richiamare i metodi che già sto predisponendo.

Eliminando i prototipi dei metodi privati, al momento la classe appare così:

Codice sorgente - presumibilmente C++

  1. #ifndef CDF_H
  2. #define CDF_H
  3.  
  4.  
  5. // un po' di costanti
  6. const char kEstensioneFileCodificato[] = "cdf";
  7. const char kEstensioneFileInChiaro[]   = "txt";
  8. enum { kNoDati, kDaCodificare, kDaDecodificare };
  9.  
  10.  
  11. class CDF {
  12.  
  13.     public:
  14.         CDF();
  15.         virtual ~CDF();
  16.  
  17.         void imposta_chiave( const char *sChiave, unsigned long l = 0xFFFFFFFF )
  18.             throw( const char* );
  19.  
  20.         void imposta_dati( const char *percDati, unsigned long l = 0xFFFFFFFF )
  21.             throw( const char* );
  22.  
  23.         void elabora( void )
  24.             throw (const char*);
  25.  
  26.         // metodi "informativi"
  27.         unsigned long lunghezza_chiave( void ) { return lChiave; }
  28.         unsigned long lunghezza_dati( void ) { return lDati; }
  29.  
  30.         int destinazione_dati( void );
  31.         const unsigned char *caratteri_mancanti( void );
  32.         unsigned int totale_caratteri_mancanti( void );
  33.  
  34.     protected:
  35.  
  36.     private:
  37.         char *chiave;               // la stringa della chiave
  38.         unsigned long lChiave;      // la quantita di caratteri nella chiave
  39.  
  40.         char *dati;                 // la stringa dei dati
  41.         unsigned long lDati;        // la quantita di caratteri nei dati
  42.  
  43.         char *percFDati;            // il percorso del file dei dati
  44.         unsigned long lPercFDati;   // la quantita di caratteri nel percorso
  45.  
  46.         int destDati;               // kNoDati, kDaCodificare, kDaDecodificare
  47.  
  48.         unsigned char carMancanti[256]; // la lista dei caratteri mancanti nella chiave
  49.         unsigned int nCarMancanti;      // la quantita dei caratteri mancanti
  50.  
  51.         void InizializzaNullo( void );
  52.         void InizializzaCaratteriMancanti( void );
  53.         int DeterminaDestinazioneDati( void );
  54.         bool ChiaveValida( void );
  55.         void Codifica( void ) throw( const char* );
  56.         void Decodifica( void ) throw( const char* );
  57.         char *CreaPercorsoFileOutput( const char *estensione );
  58. };
  59.  
  60. #endif // CDF_H




EDIT: non è che mi sto avviando verso la creazione d'una classe "blob"? Farei forse meglio a lasciare i dati a un livello ESTERNO alla classe e a passarli a questa come parametri per un processamento immediato e un altrettanto immediato abbandono? Ma, facendo così, dove sarebbe il vantaggio dell'avere una classe anziché un semplice set di funzioni?

Ultima modifica effettuata da AldoBaldo il 02/02/2015 alle 18:30


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 19:00
Lunedì, 02/02/2015
usare std::string anzichè char* dovrebbe portarti a eliminare lChiave e lDati. le stringhe della STL sono inoltre oggetti con metodi che potrebbero tornarti utili..... Io te lo dico, non si sa mai........ Nel C++11 non serve specificare il tipo delle eccezioni lanciate dai metodi, quindi niente
Codice sorgente

void elabora( void )             throw (const char*);


e così via...... InizializzaNullo sarà un metodo che chiamerai solo dal costruttore? Se si, fai un pensierino sul rimuoverlo e traslocare il suo contenuto nel costruttore. Io personalmente ti sconsiglio di gestire i file direttamente in quella classe, in quanto dovrebbe poter cifrare/decifrare un flusso di byte in memoria, non necessariamente memorizzati in un file, ma per esempio da una chat o simile.

Codice sorgente - presumibilmente C++

  1. unsigned char carMancanti[256]; // la lista dei caratteri mancanti nella chiave
  2.         unsigned int nCarMancanti;      // la quantita dei caratteri mancanti



un bel std::vector<uint8_t> carMancanti sostituirebbe egreggiamente quel codice. Quando ti serve nCarMancanti basta fare this->carMancanti.size(); e per salvare un nuovo carattere this->carMancanti.push_back(...);

PM Quote
Avatar
Roby94 (Member)
Guru


Messaggi: 1170
Iscritto: 28/12/2009

Segnala al moderatore
Postato alle 21:29
Lunedì, 02/02/2015
Passi da gigante rispetto alla prima versione, segui i consigli di Juster.

Normalmente i metodi e le proprietà pubbliche si scrivono con le iniziali maiuscole "CamelCase", e le variabili private con la prima lettera minuscola e le parole successive con la prima lettera maiuscola, i _ si adoperano nelle definizioni. Puoi scegliere di seguire queste piccole regole di ordine, ma non sei obbligato, molti coder non usano delle notazioni ordinate, ma questo non rende i loro algoritmi meno concorrenziali. Non mi azzardo assolutamente a consigliarti di usare nomi inglesi, hai gia chiarito la tua posizione XD

Juster ha sottolineato un punto importante, vuoi limitare la tua classe alla sola codifica di file o di uno stream generico?

Lasciare che sia la classe a decidere se codificare o decodificare non mi sembra un ottima idea, potrebbe precluderti delle implementazioni future, io lascerei le funzioni codifica e decodifica come pubbliche.

PM Quote