Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 11
  1. #1
    Utente di HTML.it L'avatar di Il Pazzo
    Registrato dal
    Jul 2004
    Messaggi
    1,071

    Interfacce

    Ehm... penso di averle capite.... vagamente... ma dovrei esserci (beh sono sicuro che i metodi devono essere per forza publici e gli attributi per forza final o static)... più che altro il problema sta nel fatto che non riesco a vederne l'utilità.... qualcuno potrebbe gentilmente postare un esempio concreto senza rimanere nel vago per aiutarmi a capire a che servono ste cose?


    Grazie in anticipo

  2. #2
    Una interfaccia è un'evoluzione del concetto di classe astratta. Il vantaggio che offrono sia le classi astratte che le interfacce sta nel fatto che queste possono obbligare le sottoclassi ad implementare dei comportamenti. Infatti una classe che eredita un metodo astratto deve fare l'override del metodo ereditato oppure essere dichiarata astratta essa stessa. Dal punto di vista della progettazione quindi, questi strumenti supportano l'astrazione dei dati.
    Una classe astratta solitamente non è altro che una astrazione, che è troppo generica per essere istanziata nel contesto in cui si dichiara. Un buon esempio è una classe Veicolo. Un'interfaccia invece non è una vera astrazione troppo generica per il contesto, ma semmai un'astrazione "comportamentale", che non ha senso istanziare in un certo contesto.

    Ad esempio:

    codice:
    public abstract class Veicolo{
         
         public abstract void accelera();
         public abstract void decelera();
    ...
    }
    Ora si può introdurre un'interfaccia VeicoloVolante:

    codice:
    public interface VeicoloVolante{
    
         void atterra();
         void decolla();
    }
    Ogni "veicolo" che deve astrarre il concetto di "veicolo volante" deve implementare l'interfaccia:

    codice:
    public class Aereo extends Veicolo implements VeicoloVolante{
    
         public void atterra(){
              //override del metodo di VeicoloVolante
         }
    
         public void decolla(){
              //override del metodo di VeicoloVolante
         }
    
         public void accelera(){
              //override del metodo di Veicolo
         }
    
         public void decelera(){
              //override del metodo di Veicolo
         }
    }
    Il vantaggio di tutto ciò è che così si utilizza il polimorfismo. Infatti sono lecite le seguenti dichiarazioni:

    VeicoloVolante veicVol = new Aereo();
    Veicolo veicolo = new Aereo();

  3. #3
    Utente di HTML.it L'avatar di Il Pazzo
    Registrato dal
    Jul 2004
    Messaggi
    1,071
    ok grazie... ma mi sorge un altra domanda a questo punto... non ho capito bene il concetto di astrazione... magari con un esempio...

  4. #4
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,328
    Una classe astratta è una classe che, di per se, non può essere istanziata perchè mancano delle caratteristiche atte a specificarla.
    Un buon esempio è la classe Figura.

    Non puoi, intuitivamente, istanziare una Figura perchè non stai specificando di che tipo di figura si tratta (un rettangolo? un triangolo? un cerchio?).

    Nonostante questa "astrattezza", la classe Figura ha ragione di esistere per poter raggruppare tutte le sue sottoclassi. Pensa ad esempio ad un metodo che, presa una qualsiasi figura, stampa a video la sua area, indipendentemente dalla figura passata come parametro.

    Vediamo, quindi, di concretizzare l'esempio:
    codice:
    public abstract class Figura {
       private int numLati;
       public Figura(int numLati) { this.numLati = numLati; }
       public abstract double calcolaArea();
    }
    
    public class Rettangolo extends Figura {
       private int base;
       private int altezza;
       public Rettangolo() { this(base, altezza); }
       public Rettangolo(int base, int altezza) {
          super(4);   // Ha 4 lati
          this.base = base;
          this.altezza = altezza;
       }
       public double calcolaArea() { return (double) base * altezza; }
       public String toString() { return "Rettangolo"; }
    }
    
    public class Triangolo extends Figura {
       private int base;
       private int altezza;
       public Triangolo() { this(base, altezza); }
       public Triangolo(int base, int altezza) {
          super(3);   // Ha 3 lati
          this.base = base;
          this.altezza = altezza;
       }
       public double calcolaArea() { return (double) (base * altezza) / 2; }
       public String toString() { return "Triangolo"; }
    }
    Ora, un metodo di una terza classe che volesse stampare a video l'area di una qualsiasi figura:
    codice:
    public void stampaArea(Figura f) {
       System.out.println("L'area della figura " + f + " è: " + f.calcolaArea());
    }
    
    ...
    
    Rettangolo r = new Rettangolo(4, 5);
    Tritangolo t = new Tritangolo(3, 4);
    stampaArea( r );
    stampaArea( t );
    In questo modo non mi devo preoccupare di controllare il tipo di oggetto passato: so che la figura ha un metodo calcolaArea() e lo uso. Verrà chiamato automaticamente il metodo appropriato in base alla sottoclasse che effettivamente è stata istanziata.


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  5. #5
    Utente di HTML.it L'avatar di Il Pazzo
    Registrato dal
    Jul 2004
    Messaggi
    1,071
    uhm... non ho capito bene... la classe astratta Figura non ha implementato il codice per calcolare l'area... il codice per calcolare l'area del triangolo e del rettangolo è implementato nelle sottoclassi...
    Esattamente le domande che mi sono sorte sono queste:

    Quando scrivi
    codice:
     System.out.println("L'area della figura " + f + " è: " + f.calcolaArea());
    cosa succede esattamente ? f è di tipo Figura, dunque viene richiamato il metodo calcolaArea della classe astratta, che essendo il metodo stesso astratto, non ha implementato nulla.. quindi a questo punto che succede?


    Quando invece scrivi
    codice:
    Rettangolo r = new Rettangolo(4, 5);
    Tritangolo t = new Tritangolo(3, 4);
    stampaArea( r );
    stampaArea( t );
    come fa a calcolare l'area se non è stato richiamato il metodo che calcola l'area?

  6. #6
    Quando richiami stampaArea(r) (oppure stampaArea(t)) passi un parametro di tipo Rettangolo al metodo. Dalla definizione del metodo stampaArea vedi che questo richiede di ricevere un oggetto Figura. Ora dato che un oggetto Rettangolo è una Figura (Rettangolo estende Figura), l'oggetto f è un rettangolo e quindi richiami calcolaArea() su un Rettangolo, non su Figura.

  7. #7
    Utente di HTML.it L'avatar di Il Pazzo
    Registrato dal
    Jul 2004
    Messaggi
    1,071
    ahhhh ok capito.... spettacolo...

    un ultima cosa....
    codice:
    public Triangolo() { this(base, altezza); }
       public Triangolo(int base, int altezza) {
    ...
    }
    Il senso di questo costruttore qual è? perchè questo passaggio in più?

  8. #8
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,328
    Il richiamo a quel costruttore (il passaggio in più) non è effettivamente chiaro perchè ho scritto male l'esempio.
    Forse così è più chiaro:
    codice:
    public Triangolo() { this(0, 0); }
    public Triangolo(int base, int altezza) {
    In pratica, il primo costruttore (quello senza parametri) ti permette di costruire un triangolo con base e altezza pari a 0.
    In questo modo è possibile utilizzare il costruttore senza parametri per costruire un triangolo (che nella realtà non esiste) "generico":
    codice:
    Triangolo t = new Triangolo();
    La stessa cosa per il Rettangolo: stesso mio errore, stessa correzione.


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  9. #9
    Utente di HTML.it L'avatar di Il Pazzo
    Registrato dal
    Jul 2004
    Messaggi
    1,071
    ah ok ok... ma questa cosa è valida anche per il c++??


    E.... tornando alla discussione....


    R@ve M@ster diceva;
    Quando richiami stampaArea(r) (oppure stampaArea(t)) passi un parametro di tipo Rettangolo al metodo. Dalla definizione del metodo stampaArea vedi che questo richiede di ricevere un oggetto Figura. Ora dato che un oggetto Rettangolo è una Figura (Rettangolo estende Figura), l'oggetto f è un rettangolo e quindi richiami calcolaArea() su un Rettangolo, non su Figura.
    Questa cosa non poteva essere risolto tramite un binding? Non so.. ad esempio così:
    codice:
    Figura r = new rettangolo();

  10. #10
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,328
    Originariamente inviato da Il Pazzo
    ah ok ok... ma questa cosa è valida anche per il c++??
    Certamente. E' uno dei fondamenti della Programmazione OOP.

    E.... tornando alla discussione....


    R@ve M@ster diceva;[...]

    Questa cosa non poteva essere risolto tramite un binding? Non so.. ad esempio così:
    codice:
    Figura r = new rettangolo();
    Certo, anche quel codice è corretto.
    I due codici sono assolutamente equivalenti, in questo contesto.
    Ma perdi in chiarezza: dichiarare un oggetto come se fosse un oggetto della classe madre non è la cosa più chiara del mondo (e in pratica non si usa mai perché non ha alcun senso farlo se non a scopo didattico).

    Inoltre, aver dichiarato r e t come oggetti Figura ti preclude a priori l'utilizzo su di essi dei metodi specifici di ciascuna classe (a meno di forzare un cast esplicito).
    Vediamo un esempio:

    Supponiamo di aggiungere un metodo alla classe Rettangolo, che mi dice la lunghezza della diagonale:
    codice:
    public class Rettangolo extends Figura {
       ...
       public double getDiagonale() {
          return Math.sqrt((base * base) + (altezza * altezza));
       }
    }
    Ora creiamo un oggetto Rettangolo, dichiarandolo come Figura:
    codice:
    Figura ret = new Rettangolo(4, 3);
    Se provassimo ad utilizzare il metodo getDiagonale() direttamente sull'oggetto ret otterremmo un messaggio d'errore in compilazione:
    codice:
    System.out.println("La diagonale è: " + ret.getDiagonale());
    
    ...
    
    NomeClasse.java:50: cannot resolve symbol
    symbol  : method getDiagonale ()
    location: class Figura
          System.out.println("La diagonale è: " + ret.getDiagonale());
                                                     ^
    1 error
    Questo perchè la classe Figura non ha alcun metodo chiamato getDiagonale().
    Per risolvere questo problema, siamo costretti ad utilizzare un cast esplicito:
    codice:
    System.out.println("La diagonale è: " + ((Rettangolo) ret).getDiagonale());
    Alquanto scomodo, no?


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.