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
Java - Gestione ordini di un ristorante
Forum - Java - Gestione ordini di un ristorante - Pagina 2

Pagine: [ 1 2 ] Precedente | Prossimo
Avatar
WildBlood (Normal User)
Rookie


Messaggi: 58
Iscritto: 17/02/2015

Segnala al moderatore
Postato alle 16:55
Mercoledì, 04/01/2017
Testo quotato

Postato originariamente da lumo:

Visto che probabilmente hai studiato i design pattern, uno che puoi usare per rappresentare la connessione è un singleton che per tutta la durata del programma mantenga aperta la connessione al database (quindi mantiene quella variabile conn e le altre riguardanti alle credenziali al suo interno).
Altrimenti crei l'oggetto connessione nel main del tuo programma e poi lo rendi un parametro del costruttore di tutte le classi che lo richiedono. Questo è molto migliore di un singleton perché così le dipendenze sono esplicite nel codice, eventualmente permette di fare mock testing.

In ogni caso il tuo codice è vulnerabile a SQL injection, se fosse un servizio esposto via web sarebbe un bel problema.

In ogni caso ho letto la traccia e non mi è del tutto chiaro quello che devi fare. Suppongo che il software debba avere due interfacce, una usata dai camerieri per vedere quali ordini sono stati mandati, magari quanto tempo serve al loro completamento in base alla categoria dei prodotti nell'ordine (?) e così via.
Se fosse un sistema vero però servirebbe anche un'interfaccia visibile alla cucina. Se per semplicità assumiamo che gli ordini vengano sempre accettati appena ricevuti e abbiano un tempo esatto di svolgimento, l'interfaccia è inutile perché il comportamento dei cuoci è deterministico ed è sufficiente la parte dei camerieri.
Se invece si vuole simulare in modo più veritiero il tutto, man mano che si accumulano gli ordini, gli ultimi andrebbero messo "in attesa" perché è possibile fare solo un numero massimo di preparazioni in un certo tempo.
In questo caso l'interfaccia per la cucina serve, perché il cuoco segnala ai camerieri se l'ordine è stato preso oppure no. Volendo, si può anche rilassare il determinismo e simulare un tempo random per la preparazione, in quel caso serve anche un modo per dire quando l'ordine è pronto e deve essere azionato dalla cucina.

Non mi è chiaro che ruolo abbiano l'amministratore e la categoria dei prodotti.

Considerato il tutto comunque, non penso valga la pena utilizzare un database, siccome non hai bisogno di fare query complesse sui dati ma sempicemente inserirli o rimuoverli (per quanto riguarda la coda degli oridini). Userei alcuni file di testo con un formato semplice in cui a ogni riga corrisponde una informazione.

Inoltre, hai scritto una classe per popolare il database però nella traccia non è chiaro se i camerieri e le categorie siano già presenti nel database (caso in cui puoi inserirle tu manualmente, ad esempio in dei file come dicevo prima). Semplificherebbe notevolmente il lavoro, anche perché come vedi hai già una sql injection nelle prime righe di codice che hai scritto :P



Innanzitutto ti ringrazio per i consigli e le delucidazioni, non ho scelto di usare il Singleton, ma di connettermi al database ogni qualvolta mi serve connettermi sfruttando una classe chiamata ConnectionManager, e quindi se voglio svolgere operazioni con il database (query), devo prima utilizzare questa classe per stabilire la connessione. Essendo un'applicazione non orientata al web, non ho bisogno che sia invulnerabile all'SQL In. ma comunque non sto creando un software gestionale professionale per cui non devo per forza di cose evitare anche i più piccoli bug (almeno spero XD).

Non voglio creare un'interfaccia anche per la cucina, e come mi consigli di fare darò un tempo random ad ogni ordine, in modo da semplificare il tutto. Ho già inoltre usato un database, invece di un file di testo (mi esercito anche con le query, anche se sono sempicissime queste XD).

Ancora, ho cancellato definitivamente la classe che popola il database, e ho pensato anche io alla stessa cosa, ovvero di farlo trovare già popolato al software che ne fa utilizzo, in quanto non ne fa esplicita richiesta il progetto, e mi voglio semplificare la vita.

Le tue prime soluzioni per la connessione al database sono molto interessanti, e vorrei sapere se è più consono sviluppare una soluzione come la mia (si stabilisce la connessione ogni volta che ci serve), oppure tenere aperta la connessione per tutto l'arco dell'utilizzo del software ?

PM Quote
Avatar
lumo (Member)
Expert


Messaggi: 449
Iscritto: 18/04/2010

Segnala al moderatore
Postato alle 17:07
Mercoledì, 04/01/2017
Di solito si crea una connessione che duri finché serve al programma (nel tuo caso, sempre).
Innanzitutto stabilire una connessione con il database non è velocissimo, quindi è meglio farlo solo una volta. Nel tuo caso la velocità non è un problema perché è difficile che un cameriere abbia il dito così veloce da registrare due ordini in meno di un millisecondo, ma se in futuro lavorerai ancora con database è assolutamente da evitare di riconnettersi ogni volta.

Il secondo motivo è che, come hai studiato, non bisogna mai ripetere il codice in più punti. Giustamente hai pensato a come renderlo riusabile e ti dico la risposta: in questo caso è sufficiente una classe con un singolo metodo statico che ritorni l'oggetto che rappresenta la connessione.
Tuttavia con questa soluzione ripeti comunque dappertutto la chiamata che inizializza la connessione e quindi come prima hai ripetizione, sebbene molto minore. A questo punto il problema non è tanto ripetere una riga di codice, ma introdurre in più punti un punto di fallimento che invece puoi gestire in un unico punto del programma (il main, se adotti la mia soluzione).

In pratica, mi connetterei solo una volta all'inizio del programma e poi darei ai vari oggetti un reference alla connessione.

PM Quote
Avatar
WildBlood (Normal User)
Rookie


Messaggi: 58
Iscritto: 17/02/2015

Segnala al moderatore
Postato alle 2:43
Giovedì, 05/01/2017
Testo quotato

Postato originariamente da lumo:

Di solito si crea una connessione che duri finché serve al programma (nel tuo caso, sempre).
Innanzitutto stabilire una connessione con il database non è velocissimo, quindi è meglio farlo solo una volta. Nel tuo caso la velocità non è un problema perché è difficile che un cameriere abbia il dito così veloce da registrare due ordini in meno di un millisecondo, ma se in futuro lavorerai ancora con database è assolutamente da evitare di riconnettersi ogni volta.

Il secondo motivo è che, come hai studiato, non bisogna mai ripetere il codice in più punti. Giustamente hai pensato a come renderlo riusabile e ti dico la risposta: in questo caso è sufficiente una classe con un singolo metodo statico che ritorni l'oggetto che rappresenta la connessione.
Tuttavia con questa soluzione ripeti comunque dappertutto la chiamata che inizializza la connessione e quindi come prima hai ripetizione, sebbene molto minore. A questo punto il problema non è tanto ripetere una riga di codice, ma introdurre in più punti un punto di fallimento che invece puoi gestire in un unico punto del programma (il main, se adotti la mia soluzione).

In pratica, mi connetterei solo una volta all'inizio del programma e poi darei ai vari oggetti un reference alla connessione.  



Capisco, essendo però che si tratta di un progetto universitario (da consegnare per un esame), dovrebbe comunque andar bene la soluzione da me sviluppata. Però vorrei capire come dare ai vari oggetti un reference alla connessione.

Un esempio è la classe che mostra il nome e il cognome di un cameriere dato il suo codice identificativo (l'ho pensata come azione che può compiere l'amministratore). Nella classe che consente di connettersi al database ho questo metodo:

Codice sorgente - presumibilmente Java

  1. public static Connection getConnection() {
  2.         try {
  3.             Class.forName(JDBC_DRIVER);
  4.             try {
  5.                 con = DriverManager.getConnection(DB_URL, USER, PASS);
  6.                 System.out.println("Connessione stabilita.");
  7.             } catch (SQLException ex) {
  8.                 System.out.println("Impossibile connettersi al database.");
  9.             }
  10.         } catch (ClassNotFoundException ex) {
  11.             System.out.println("Driver non trovato.");
  12.         }
  13.         return con;
  14.     }



Ovviamente le variabili le definisco. Mentre nel blocco TRY del metodo getInformation (viene utilizzato per stampare nome e cognome del cameriere dato il suo codice identificativo), connetto prima il database e poi faccio tutte le altre operazioni:

Codice sorgente - presumibilmente Java

  1. ConnectionManager nuovaConnessione = new ConnectionManager();
  2.             con = nuovaConnessione.getConnection();
  3.             stmt = con.createStatement();
  4.            
  5.             // Inserimento dei dati.
  6.             String sql = "SELECT * FROM camerieri";
  7.             rs = stmt.executeQuery(sql);
  8.             System.out.println("Operazione eseguita con successo..");



Stabilisco la connessione (attraverso il codice delle prime tre righe) li dove mi serve usare la connessione.
Potrebbe andar bene come soluzione ?

Inoltre vorrei chiedere delucidazioni sull'utilizzo di quei design pattern (Observer e Chain of Responsability) e come dovrei implementarli per adattarli alla mia applicazione.

PM Quote
Avatar
lumo (Member)
Expert


Messaggi: 449
Iscritto: 18/04/2010

Segnala al moderatore
Postato alle 16:08
Giovedì, 05/01/2017
Quando hai un metodo statico non serve che crei un'istanza della classe, anche perché non avrebbe senso avere un oggetto senza stato (come in questo caso). Si fa semplicemente
Codice sorgente - presumibilmente Plain Text

  1. con = Connession.getConnection();


Siccome Connession non rappresenta nessuna connessione vera e propria, potresti di fatto darci un nome tipo ConnessionManager.
A questo punto vedi che la distanza dal singleton è poca, però in questo caso non serve visto che ricrei ogni volta la connessione.

In ogni caso continuo a pensare che sia una scelta sbagliata soprattutto per un esercizio dove devi mostrare che capisci i principi di software engineering.

Il tuo codice mostra perfettamente perché non va bene: nel caso fallisca la connessione al database, ritorni un oggetto nullo.
Quindi per correggere questo, bisogna piazzare un
Codice sorgente - presumibilmente Java

  1. if (conn != null) { ... }


dappertutto dove ne fai uso. E ritorniamo alla ripetizione, per quel discorso del punto di fallimento che facevo nel post precedente.

Allora potresti pensare ,magari invece di stampare un errore faccio un bel System.exit o come si chiama in Java, il che è una soluzione ancora peggiore perché potrebbe tagliare le gambe al programma che magari aveva già stabilito delle connessioni funzionanti.

Secondo me dovresti creare la connessione all'inizio del programma, in caso di fallimento uscire subito oppure riprovare un numero fisso di volte prima di uscire.
A quel punto hai un oggetto valido che puoi passare a tutti gli altri tuoi oggetti e useranno quello.

Uso la classe popolaCamerieri come esempio anche se l'hai rimossa, si applica alle altre classi che hai formato:
Codice sorgente - presumibilmente Java

  1. public class popolaCamerieri {  
  2.     private Connection conn;
  3.  
  4.     public popolaCamerieri(Connection parentConnection) {
  5.         this.conn = parentConnection;
  6.     }
  7.     ....
  8. }


E nel codice che usava il database, usi this.conn.

Spero di averti convinto questo giro :rotfl:

Per quanto riguarda i design pattern, a me fanno schifo quindi lascio a te l'ingrato compito di utilizzarli.
Secondo me il consiglio che ti aveva dato Goblin è giustissimo, cioè prima fai il programma usando semplicemente i principi di programmazione ad oggetti. Se li usi correttamente, i pattern giusti emergeranno da soli e a quel punto sta a te riconoscerli.
Quasi mai i pattern si applicano perfettamente al problema, di solito richiedono modifiche o adattamenti e secondo me sarebbe molto più interessante discutere queste cose.

So che la tentazione di finire in fretta sbattendo i pattern qua è là probabilmente ce l'hai, però il pattern lo puoi applicare solo una volta che hai già definito bene l'implementazione e non mi pare che tu abbia già le idee completamente chiare sul programma.
Se implementare prima tutto ti sembra troppo, completa solo una parte significativa lasciando il resto da fare, dopodiché inserisci i pattern e poi completa.

Ultima modifica effettuata da lumo il 05/01/2017 alle 16:09
PM Quote
Avatar
WildBlood (Normal User)
Rookie


Messaggi: 58
Iscritto: 17/02/2015

Segnala al moderatore
Postato alle 17:49
Giovedì, 05/01/2017
Testo quotato

Postato originariamente da lumo:

Quando hai un metodo statico non serve che crei un'istanza della classe, anche perché non avrebbe senso avere un oggetto senza stato (come in questo caso). Si fa semplicemente
Codice sorgente - presumibilmente Plain Text

  1. con = Connession.getConnection();


Siccome Connession non rappresenta nessuna connessione vera e propria, potresti di fatto darci un nome tipo ConnessionManager.
A questo punto vedi che la distanza dal singleton è poca, però in questo caso non serve visto che ricrei ogni volta la connessione.

In ogni caso continuo a pensare che sia una scelta sbagliata soprattutto per un esercizio dove devi mostrare che capisci i principi di software engineering.

Il tuo codice mostra perfettamente perché non va bene: nel caso fallisca la connessione al database, ritorni un oggetto nullo.
Quindi per correggere questo, bisogna piazzare un
Codice sorgente - presumibilmente Java

  1. if (conn != null) { ... }


dappertutto dove ne fai uso. E ritorniamo alla ripetizione, per quel discorso del punto di fallimento che facevo nel post precedente.

Allora potresti pensare ,magari invece di stampare un errore faccio un bel System.exit o come si chiama in Java, il che è una soluzione ancora peggiore perché potrebbe tagliare le gambe al programma che magari aveva già stabilito delle connessioni funzionanti.

Secondo me dovresti creare la connessione all'inizio del programma, in caso di fallimento uscire subito oppure riprovare un numero fisso di volte prima di uscire.
A quel punto hai un oggetto valido che puoi passare a tutti gli altri tuoi oggetti e useranno quello.

Uso la classe popolaCamerieri come esempio anche se l'hai rimossa, si applica alle altre classi che hai formato:
Codice sorgente - presumibilmente Java

  1. public class popolaCamerieri {  
  2.     private Connection conn;
  3.  
  4.     public popolaCamerieri(Connection parentConnection) {
  5.         this.conn = parentConnection;
  6.     }
  7.     ....
  8. }


E nel codice che usava il database, usi this.conn.

Spero di averti convinto questo giro :rotfl:

Per quanto riguarda i design pattern, a me fanno schifo quindi lascio a te l'ingrato compito di utilizzarli.
Secondo me il consiglio che ti aveva dato Goblin è giustissimo, cioè prima fai il programma usando semplicemente i principi di programmazione ad oggetti. Se li usi correttamente, i pattern giusti emergeranno da soli e a quel punto sta a te riconoscerli.
Quasi mai i pattern si applicano perfettamente al problema, di solito richiedono modifiche o adattamenti e secondo me sarebbe molto più interessante discutere queste cose.

So che la tentazione di finire in fretta sbattendo i pattern qua è là probabilmente ce l'hai, però il pattern lo puoi applicare solo una volta che hai già definito bene l'implementazione e non mi pare che tu abbia già le idee completamente chiare sul programma.
Se implementare prima tutto ti sembra troppo, completa solo una parte significativa lasciando il resto da fare, dopodiché inserisci i pattern e poi completa.



Grazie mille per i consigli, ho corretto il codice. Però continuo a non capire come posso stabilire all'inizio del programma la connessione al database, del tipo, dovrei stabilire la connessione al database nel Main, per poi passare la connessione ad ogni classe che deve operare su di esso (database).

Un'altra cosa poi. Essendo che sto sviluppando un'applicazione standalone con supporto grafico, dovrei usare Java Swing per disegnare la GUI del programma. Ho scritto nel Main:

Codice sorgente - presumibilmente Java

  1. public static void main(String[] args) {  
  2.         JFrame frame = new JFrame("Login");
  3.         JButton btnLoginAdmin = new JButton("Amministratore");
  4.         JButton btnLoginServer = new JButton("Cameriere");
  5.  
  6.         btnLoginAdmin.addActionListener(
  7.                 new ActionListener(){
  8.                     public void actionPerformed(ActionEvent e) {
  9.                         LoginWindow newLogin = new LoginWindow(1);
  10.                         newLogin.setVisible(true);
  11.                     }
  12.                 });
  13.        
  14.         btnLoginServer.addActionListener(
  15.                 new ActionListener(){
  16.                     public void actionPerformed(ActionEvent e) {
  17.                         LoginWindow newLogin = new LoginWindow(2);
  18.                         newLogin.setVisible(true);
  19.                     }
  20.                 });
  21.  
  22.         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  23.         frame.setSize(300, 100);
  24.         frame.setLayout(new FlowLayout());
  25.         frame.getContentPane().add(btnLoginAdmin);
  26.         frame.getContentPane().add(btnLoginServer);
  27.         frame.setVisible(true);
  28.     }



Ovviamente la classe LoginWindow tiene conto del fatto che si stia eseguendo il login come amministratore o come cameriere, ed ecco il codice principale:

Codice sorgente - presumibilmente Java

  1. btnLogin.addActionListener(new ActionListener() {
  2.             public void actionPerformed(ActionEvent e) {
  3.             Login newAccess = new Login(getUsername(), getPassword(), UserChose);
  4.             int AccessEx = newAccess.startLogin();
  5.             if (AccessEx == 1) {
  6.                     JOptionPane.showMessageDialog(LoginWindow.this, "Accesso eseguito come amministratore." , "Login", JOptionPane.INFORMATION_MESSAGE);
  7.                     dispose();
  8.             } else if (AccessEx == getUsername()) {
  9.                     JOptionPane.showMessageDialog(LoginWindow.this, "Accesso eseguito come cameriere N. " + getUsername(), "Login", JOptionPane.INFORMATION_MESSAGE);
  10.                     dispose();
  11.             } else {
  12.                     JOptionPane.showMessageDialog(LoginWindow.this, "ID USER o PASSWORD non valido.", "Login", JOptionPane.ERROR_MESSAGE);
  13.                     tfUsername.setText("");
  14.                     pfPassword.setText("");
  15.                 }
  16.             }
  17.         });



Potrebbe andar bene ?! Nonostante la ripetizione di codice nel Main.

Ultima modifica effettuata da WildBlood il 05/01/2017 alle 21:07
PM Quote
Pagine: [ 1 2 ] Precedente | Prossimo