Enrera
Mòdul 4
Iniciació a la programació en Java
  Pràctica
1
2
3
4
   
Exercicis
Exercicis
 
 
  Les interfícies (interfaces)
   

Un dels mecanismes d'herència més interessants i potents són les interfícies (interfaces). Una interfície és un tipus una mica especial de classe que conté noms de mètodes, llistes de paràmetres, tipus de retorn, però sense el cos dels mètodes. És un objecte que té forma, però no té contingut.

La seva feina és dir: "Aquest aspecte que tinc, és el que han de tenir les classes que m'implementin". És una maqueta, una especificació i res més.

Les interfícies són molt útils per recollir les similituds entre classes que no estan vinculades per herència i per a donar plasticitat. Una classe pot implementar més d'una interfície, en un model que recull parcialment l'herència múltiple de C++.

   
  Tot declarant una interfície (interface)

Imaginem que rebem un encàrrec del director de l'institut: necessita una eina que li faci el recompte del nombre d'hores d'absència al centre de qualsevol persona que hi treballa, sigui professor, alumne o personal no docent.

En fer l'anàlisi de la comanda observem que disposem de tota la informació necessària per a escriure el programa: tenim diferents taules Access amb les llistes de professors, alumnes i personal no docent i taules on hem anat enregistrant totes i cadascuna de les hores d'absència.

Els formats, però, no són idèntics: no quantifiquem al mateix lloc ni de la mateixa forma les hores d'absència d'un professor que les d'un alumne o les d'un administratiu. Per tant, els programes de recompte no podran ser iguals per a un professor, un alumne o un membre del PAS.

Resoldrem la situació a través de la creació d'una interfície, que ens simplificarà una mica la feina i ens permetrà construir una solució elegant i llegible. Seguirem els passos seguents:

  • En primer lloc hem d'imaginar un usuari ideal, abstracte, al qual se li ha de poder aplicar el mecanisme de càlcul d'hores d'absència. A aquest usuari ideal li direm Usuari i farem que tots els membres del nostre institut en formin part.

  • Després crearem tres classes diferents Professor, Alumne i Pas, que s'ajustin a la definició abstracta d'Usuari -és a dir, que implementin la interfície Usuari- i que resolguin, cadascuna de la seva forma, la manera de recomptar les absencies.

  • Seguidament farem una classe ControlAbsencies que servirà per a recomptar absencies, sigui quin sigui el tipus d'usuari

  • Finalment escriurem un programa LesAbsenciesDe que aplica ControlAbsencies per a diferents tipus d'usuaris.

Obrim JCreator i creem un projecte on anirem deixant tots els fitxers de la pràctica. Creem, en primer lloc, el nostre Usuari en forma d'interfície; escrivim a Usuari.java el codi següent:

 

import java.util.Date;

public interface Usuari {

    int absencies(Date dia1, Date dia2);

}

   
  Implementant una interfície (interface):
   
 

Observeu la senzillesa del que hem fet: hem creat una interfície pública que es diu Usuari i que té un sol element, un mètode que es diu absencies(Date dia1, Date dia2). No escrivim com es fa el càlcul de les absències perquè no es problema de la interfície, cada classe que la implementi ho farà de la seva pròpia forma.

A partir d'ara si volem que alguna classe implementi Usuari haurà de definir obligatòriament un mètode absencies(Date dia1, Date dia2) que tingui exactament la mateixa forma que a la interfície, sinó, no podrà ni compil·lar-se.

Ara que ja tenim l'usuari abstracte, farem el segon pas: crearem les formes concretes de Professor, Alumne i Pas.

La classe Professor:

import java.util.Date;

class Professor implements Usuari {

    public int absencies(Date dia1, Date dia2) {
        // Aquí hi aniria el mecanisme de càlcul propi pels professors
        // El resultat que retornem és fictici

        return 25;
    }

}

   
  Observeu que hem dit que la nova classe Professor implementa l'interfície Usuari. Per tal que Java ens deixi compil·lar, li hem de definir un mètode absencies(Date dia1, Date dia2). Amb això ens ajustem a l'estandar de la interfície. D'aquesta forma proposem també la solució concreta al càlcul d'absències per a professors.
   
Un dels avantatges que té JCreator Professional és que conté un expert d'implementació d'interfícies similar a l'expert de creació de classes de la versió Lite; donada una classe i indicant-li la interfície que implementarà, el JCreator Professional ens crea l'estructura de mètodes obligatoris. En el nostre exemple, aquest expert no tindria molta utilitat. Imagineu, però, una interfície que tingui vint mètodes!
   
  La classe Alumne:
   
 

import java.util.Date;

class Alumne implements Usuari {

    public int absencies(Date dia1, Date dia2) {
        // Aquí hi va el mecanisme de càlcul propi pels alumnes
        // El resultat torna a ser fictici

        return 73;
    }

}

   
  La classe Pas:
   
 

import java.util.Date;

class Pas implements Usuari {

    public int absencies(Date dia1, Date dia2) {
        // Aquí va el mecanisme de càlcul propi pel PAS
        // El resultat torna a ser fictici

        return 34;
    }

}

   
  Ara que ja hem creat les classes amb cada mètode particular de càlcul d'absències, farem el tercer pas, la creació d'una classe que serveix per a retornar les absències de qualsevol tipus d'usuari:
   
 
import java.util.Date;

public class ControlAbsencies {

    private Usuari usuari;

    public ControlAbsencies(Usuari usuari) {
        this.usuari = usuari;
    }

    public int getAbsencies(Date dia1, Date dia2) {
        return usuari.absencies(dia1,dia2);
    }

}

   
 

Aquí ens trobem amb alguns dels aspectes que demostren la potència de les interfícies:

  • La classe que acabem de crear retorna el número d'absències, sigui l'usuari un alumne, un professor o un membre del PAS. Per al programador, tots són usuaris, només hem de cridar a un sol mètode getAbsencies() per a qualsevol d'ells. Això simplifica enormement el disseny del programa.

  • Hem encapsulat el nostre problema: qualsevol programa que escriguem podrà utilitzar aquesta classe, ControlAbsencies sense haver-se de preocupar de quins mecanismes de càlcul hi ha per darrera o si són mètodes idèntics o particulars per a cada tipus d'usuari.

    És més, si en algun moment remodelem les nostres bases de dades i canviem la manera d'enregistrar les absències o el mètode de càlcul, no farà falta tocar ni una sola línia de ControlAbsencies ni de cap classe que la utilitzi com a eina. Només tocarem la classe particular d'usuari. Això facilita moltíssim la feina al programador, que pot localitzar i circumscriure amb facilitat els fragments de codi que ha de canviar o mantenir, amb la tranquil·litat que els canvis no tindran efectes col·laterals en el programa que està escrivint.

Finalment en comprovem el funcionament amb el programa Informes.java.

   
import java.util.Date;
import java.text.SimpleDateFormat;
import java.text.ParsePosition;

public class Informes {

    public static void main(String args[]) {
        Alumne alumne = new Alumne();
        Professor professor = new Professor();
        Pas pas = new Pas();

        SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy");
        ParsePosition pos = new ParsePosition(0);
        Date dia1 = df.parse("01-09-2002",pos);
        pos = new ParsePosition(0);
        Date dia2 = df.parse("30-06-2002",pos);

        System.out.println("L'alumne ha fet: "+
               new ControlAbsencies(alumne).getAbsencies(dia1, dia2)+
               "absències aquest curs");

        System.out.println("El professor ha fet: "+
            new ControlAbsencies(professor).getAbsencies(dia1, dia2)+
            " absències aquest curs");

        System.out.println("El PAS ha fet: "+
                  new ControlAbsencies(pas).getAbsencies(dia1, dia2)+
                  " absències aquest curs");
    }

}

   
  Compileu i executeu el programa. Observareu com la classe ControlAbsencies va aplicant el mecanisme de càlcul particular de cada tipus d'usuari.
   
Els programadors novells, quan comencen a estudiar objectes, tendeixen a fer dissenys de classes que utilitzen intensivament els atributs d'herència, potser els més intuïtius d'aquest tipus de programació. Però està demostrat que l'abús de l'herència complica bastant el disseny i la legibilitat dels programes. D'entrada, és més pràctic pensar dissenys horitzontals, on unes classes utilitzen altres classes, i utilitzar interfícies per agrupar comportaments i donar poca profunditat als arbres d'herència.
   
  Algunes característiques de les interfícies (interfaces)
   
  • Una interfície pot extendre altres interfícies, i no només una sola. Això seria correcte:

    public interface Constantsutils extends ConstantsPetites,
                                            ConstantsGrans {
        public final double ALTURA = 3.15;
        public final int RADI = 34;

    }

  • Una interfície no pot extendre classes.

  • Una interfície hereta tots els mètodes i constants de les superinterfícies, excepte si els sobreescriu (override).

  • Tots els mètodes declarats en una interfície són, per defecte, public abstract. No es permeten altres tipus com private o protected.

  • Com que els camps (fields) en una interfície són automàticament static i constants, la interfície ens anirà bé per a la creació de grups de valors constants:

    public interface Setmana {

        int DILLUNS = 1, DIMARTS=2, DIMECRES=3,
            DIJOUS=4, DIVENDRES=5, DISSABTE=6, DIUMENGE=7;

    }

  • Tot i ser constants, els camps (fields) de les interfícies es poden inicialitzar amb valors no constants, valors que prendran el primer cop que es carregui una classe que implementi la interfície:

    public interface Atzar {

        int enter = (int) (Math.random()*1000);

    }

   
 
Amunt