Conceptos básicos de Java & Spring Framework – Interfaces

Interfaces en Java

Este concepto es muy importante en Java ya que lo estarás utilizando a diestra y siniestra para desarrollar aplicaciones con Spring. Una interfaz en java no es una clase, más bien es un conjunto de declaraciones de métodos en un archivo. En las interfaces se especifica que debe hacerse pero no como se hace. Serán las clases que implementen estas interfaces las que describan la lógica del comportamiento de los métodos declarados en la interfaz. Las palabras clave que java tiene reservadas para utilizar interfaces son interface e implements.

La sintaxis para declarar una interface es:

modificador_acceso interface NombreInterfaz {
	//declaracion de metodos 
}

Dónde:

modificador_acceso Se refiere al ámbito de la interfaz private o public
interface Es la palabra reservada que java tiene para declarar interfaces
NombreInterfaz Es el nombre de la interfaz

La sintaxis para declarar que una clase implementa una interfaz es:

modificador_acceso class NombreClase implements NombreInterfaz {
	//implementación de métodos 
}

Dónde:

modificador_acceso Se refiere al ámbito de la clase private o public
NombreClase Es el nombre de la clase que implementara los métodos declarados en NombreInterfaz
implements Es la palabra reservada que java tiene para indicar que se van a implementar los métodos de una interfaz
NombreInterfaz Es el nombre de la interfaz que se va a implementar

Nuevamente, para que quede más claro, a continuación dejo un ejemplo muy sencillo de declaración e implementación de interfaces en Java. Básicamente ejemplifica los siguientes conceptos:

  • La herencia entre interfaces
  • La herencia entre clases
  • Como declarar una interfaz
  • Como implementar una interfaz
  • Como obtener una referencia a una interfaz

El ejemplo se compone de 4 interfaces y 6 clases, para entenderlo mejor observa en la siguiente imagen (diagrama de clases UML) como se relacionan entre sí los archivos:

Diagrama de clases del ejemplo con interfaces de java

En el diagrama anterior se usan algunos elementos UML como Clases, Interfaces, Asociaciones, Agregaciones y Realizaciones, temas que no abordare aquí en profundidad, pero si quiero dejar unas cuantas explicaciones rápidas acerca de las asociaciones UML del diagrama:

  • Linea punteada indica implementación
  • Linea continua indica herencia
  • Linea que inicia con flecha en forma de diamante indica que contiene una o mas de la clase donde termina dicha linea
  1. Todas las interfaces heredan de la interfaz IDispositivo (lineas azules)
  2. Todas las clases heredan de la clase Dispositivo (lineas moradas)
  3. Debido al punto 1; todas las clases (a excepción de Dispositivo.java) implementan a la interfaz IDispositivo de forma indirecta (a través de una subinterface)

Haz zoom sino distingues los colores.
He resaltado con morado la asociación de herencia entre clases
He resaltado con azul la asociación de herencia entre interfaces

Bueno sin mas preámbulos a continuación muestro los archivos fuente:

IDispositivo.java – Declaración de Interfaz

/*
 www.notas-programacion.com
 Descripción:
    Ejemplo con interfaces en java
 Archivo: IDispositivo.java
 */

package com.notasprogramacion.interfaces.test;

public interface IDispositivo {
    
    public boolean encender();
    public boolean apagar();
    public void funcionar();
    
}

Esta interfaz es la raíz de todas las interfaces no hereda ni extiende a nada, solo declara 3 métodos.

IDispositivoAlmacenamiento.java – Declaración de Interfaz y herencia entre interfaces

/*
 www.notas-programacion.com
 Descripción:
    Ejemplo con interfaces en java. En java la herencia entre interfaces 
    también esta permitida.  Observa como esta interfaz hereda de IDispositivo. 
    Todos los métodos declarados en la clase padre ahora también los tiene esta interfaz.
 Archivo: IDispositivoAlmacenamiento.java
 */

package com.notasprogramacion.interfaces.test;

public interface IDispositivoAlmacenamiento extends IDispositivo {
    
    public boolean escritura();
    public boolean lectura();
    
}

Esta interfaz extiende a la interfaz raíz IDispositivo por lo tanto todas las clases que quieran implementar esta interfaz deben implementar los 3 métodos de la raíz mas los 2 métodos declarados aquí, en total 5.

IMicroprocesador.java – Declaración de Interfaz y herencia entre interfaces

/*
 www.notas-programacion.com
 Descripción:
    Ejemplo con interfaces en java. En java la herencia entre interfaces 
    también esta permitida.  Observa como esta interfaz hereda de IDispositivo. 
    Todos los métodos declarados en la clase padre ahora también los tiene esta interfaz.
 Archivo: IMicroprocesador.java
 */

package com.notasprogramacion.interfaces.test;

import com.notasprogramacion.interfaces.IDispositivo;

public interface IMicroprocesador extends IDispositivo {
    
    public void procesar();
    
}

Esta interfaz extiende a la interfaz raíz IDispositivo por lo tanto todas las clases que quieran implementar esta interfaz deben implementar los 3 métodos de la raíz mas el método declarado aquí, en total 4.

IComputadora.java – Declaración de Interfaz y herencia entre interfaces

/*
 www.notas-programacion.com
 Descripción:
    Ejemplo con interfaces en java. En java la herencia entre interfaces 
    también esta permitida.  Observa como esta interfaz hereda de IDispositivo. 
    Todos los métodos declarados en la clase padre ahora también los tiene esta interfaz.
 Archivo: IComputadora.java
 */

package com.notasprogramacion.interfaces.test;

public interface IComputadora extends IDispositivo {

    public abstract void graficar();
    public void guardarDocumento();
    public void chatear();
    public void navegar();
    public void reproducirMusica();
    public void reproducirVideo();
    public abstract void abrirPrograma();
    // ...etc
}

Esta interfaz extiende a la interfaz raíz IDispositivo por lo tanto todas las clases que quieran implementar esta interfaz deben implementar los 3 métodos de la raíz mas los 7 métodos declarados aquí, en total 10.

En las siguientes clases la palabra clave @Override (en español sobreescribir) es una anotación de java e indica que el método escrito a continuación se esta sobre-escribiendo porque se declaro vació (vaya, sin implementar) en alguna interfaz. Para guiarte sobre que métodos se están implementando puedes buscar visualmente esta anotación y las veces que aparezca es la cantidad de métodos implementados.

DiscoDuro.java – Implementación de Interfaz y herencia entre clases

/*
 www.notas-programacion.com
 Descripción:
    Ejemplo con interfaces en java. La palabra implements es la palabra reservada que tiene java 
    para implementar los métodos de una interfaz
 Archivo: DiscoDuro.java
 */

package com.notasprogramacion.interfaces.test;

public class DiscoDuro extends Dispositivo implements IDispositivoAlmacenamiento  {
    private int capacidad;

    @Override
    public boolean encender() {
        System.out.println("Disco duro encendido");
        return true;
    }

    @Override
    public boolean apagar() {
        System.out.println("Disco duro apagado");
        return true; 
    }

    @Override
    public void funcionar() {
       System.out.println("Disco duro funcionando");
    }

    @Override
    public boolean escritura() {
        System.out.print("Escribiendo en Disco duro");
        return true;
    }

    @Override
    public boolean lectura() {
        System.out.print("Leyendo Disco duro");
        return true;
    }

    public int getCapacidad() {
        return capacidad;
    }

    public void setCapacidad(int capacidad) {
        this.capacidad = capacidad;
    }
    
}

Esta clase extiende a la clase Dispositivo.java e implementa a la interfaz IDispositivoAlmacenamiento por lo tanto debe implementar 5 métodos. Observa que se ha declarado 1 atributo con su getter y setter.

MemoriaRAM.java – Implementación de Interfaz y herencia entre clases

/*
 www.notas-programacion.com
 Descripción:
    Ejemplo con interfaces en java. La palabra implements es la palabra reservada que tiene java 
    para implementar los metodos de una interfaz
 Archivo: MemoriaRAM.java
 */

package com.notasprogramacion.interfaces.test;

public class MemoriaRAM extends Dispositivo implements IDispositivoAlmacenamiento {
    private int capacidad;

    @Override
    public boolean encender() {
        System.out.println("Memoria RAM encendida");
        return true;
    }

    @Override
    public boolean apagar() {
        System.out.println("Memoria RAM apagada");
        return true; 
    }

    @Override
    public void funcionar() {
       System.out.println("Memoria RAM funcionando");
    }

    @Override
    public boolean escritura() {
        System.out.println("Escribiendo en Memoria RAM");
        return true;
    }

    @Override
    public boolean lectura() {
        System.out.println("Leyendo Memoria RAM");
        return true;
    }

    public int getCapacidad() {
        return capacidad;
    }

    public void setCapacidad(int capacidad) {
        this.capacidad = capacidad;
    }

}

Esta clase extiende a la clase Dispositivo.java e implementa a la interfaz IDispositivoAlmacenamiento por lo tanto debe implementar 5 métodos. Observa que se ha declarado 1 atributo con su getter y setter.

Microprocesador.java – Implementación de Interfaz y herencia entre clases

/*
 www.notas-programacion.com
 Descripción:
    Ejemplo con interfaces en java. La palabra implements es la palabra reservada que tiene java 
    para implementar los métodos de una interfaz
 Archivo: Microprocesador.java
 */

package com.notasprogramacion.interfaces.test;

public class Microprocesador extends Dispositivo implements IMicroprocesador {
    
    private int velocidad;

    @Override
    public boolean encender() {
        System.out.println("Microprocesador encendido");
        return true;
    }
    
    @Override
    public boolean apagar() {
        System.out.println("Microprocesador apagado");
        return true;
    }
    
    @Override
    public void funcionar() {
        System.out.println("Microprocesador funcionando");
    }

    @Override
    public void procesar() {
        System.out.println("procesando...");
    }

    public int getVelocidad() {
        return velocidad;
    }

    public void setVelocidad(int velocidad) {
        this.velocidad = velocidad;
    }

}

Esta clase extiende a la clase Dispositivo.java e implementa a la interfaz IMicroprocesador por lo tanto debe implementar 4 métodos. Observa que se ha declarado 1 atributo con su getter y setter.

Dispositivo.java – Implementación de Interfaz

/*
 www.notas-programacion.com
 Descripción:
    Ejemplo con interfaces en java. La palabra implements es la palabra reservada que tiene java 
    para implementar los metodos de una interfaz.
 Archivo: Dispositivo.java
 */

package com.notasprogramacion.interfaces.test;

public class Dispositivo implements IDispositivo{

    private int id;
    private String nombre;
    private String modelo;
    private String fabricante;
    
    @Override
    public boolean encender() {
        return false;
    }

    @Override
    public boolean apagar() {
        return false;
    }

    @Override
    public void funcionar() {
        
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public String getModelo() {
        return modelo;
    }

    public void setModelo(String modelo) {
        this.modelo = modelo;
    }

    public String getFabricante() {
        return fabricante;
    }

    public void setFabricante(String fabricante) {
        this.fabricante = fabricante;
    }
    
}

Esta clase solo implementa a la interfaz IDispositivo por lo tanto debe implementar solo 3 métodos. Observa que se han declarado 4 atributos con sus getters y setters.

Computadora.java – Implementación de Interfaz y herencia entre clases

/*
 www.notas-programacion.com
 Descripción:
    Ejemplo con interfaces en java. La palabra implements es la palabra reservada que tiene java 
    para implementar los metodos de una interfaz, la palabra extends permite implementar herencia entre clases.
 Archivo: Computadora.java
 */

package com.notasprogramacion.interfaces.test;

public class Computadora extends Dispositivo implements IComputadora {
    
    private int id;
    private MemoriaRAM memoriaRam;
    private DiscoDuro discoDuro;
    private Microprocesador micropocesador;
    
    @Override
    public boolean encender() {
        System.out.println("\nEncendiendo dispositivos...");
        this.getDiscoDuro().encender();
        this.getMemoriaRam().encender();
        this.getMicropocesador().encender();
        this.getDiscoDuro().funcionar();
        this.getMemoriaRam().funcionar();
        this.getMicropocesador().funcionar();
        System.out.println("Computadora encendida...\n");
        return true;
    }

    @Override
    public boolean apagar() {
        System.out.println("\nApagando dispositivos...");
        this.getDiscoDuro().apagar();
        this.getMemoriaRam().apagar();
        this.getMicropocesador().apagar();
        System.out.println("Computadora apagada.\n\n");
        return true; 
    }

    @Override
    public void funcionar() {
       System.out.println("\nComputadora funcionando \n");
    }


    @Override
    public void guardarDocumento() {
        
    }

    @Override
    public void graficar() {
        
    }

    @Override
    public void chatear() {
        
    }

    @Override
    public void navegar() {
        
    }

    @Override
    public void reproducirMusica() {
        
    }

    @Override
    public void reproducirVideo() {
        
    }

    @Override
    public void abrirPrograma() {
        
    }
    
    @Override
    public int getId() {
        return id;
    }

    @Override
    public void setId(int id) {
        this.id = id;
    }
    public MemoriaRAM getMemoriaRam() {
        return memoriaRam;
    }

    public void setMemoriaRam(MemoriaRAM memoriaRam) {
        this.memoriaRam = memoriaRam;
    }

    public DiscoDuro getDiscoDuro() {
        return discoDuro;
    }

    public void setDiscoDuro(DiscoDuro discoDuro) {
        this.discoDuro = discoDuro;
    }

    public Microprocesador getMicropocesador() {
        return micropocesador;
    }

    public void setMicropocesador(Microprocesador micropocesador) {
        this.micropocesador = micropocesador;
    }

    @Override
    public String toString() {
        return "Computadora{ \n[ DiscoDuro{ "
                + "id = " +this.getDiscoDuro().getId() + ","
                + "nombre = " +this.getDiscoDuro().getNombre() + ","
                + "capacidad = " +this.getDiscoDuro().getCapacidad() + " GB,"                
                + "modelo= " +this.getDiscoDuro().getModelo() + ","
                + "fabricante= " +this.getDiscoDuro().getFabricante()
                + " } ], \n[ MemoriaRAM{ "
                + "id = " +this.getMemoriaRam().getId() + ","
                + "nombre = " +this.getMemoriaRam().getNombre() + ","
                + "capacidad = " +this.getMemoriaRam().getCapacidad() + " GB,"                
                + "modelo= " +this.getMemoriaRam().getModelo() + ","
                + "fabricante= " +this.getMemoriaRam().getFabricante()
                + " } ], \n[ Microprocesador{ "
                + "id = " +this.getMicropocesador().getId() + ","
                + "nombre = " +this.getMicropocesador().getNombre() + ","
                + "velocidad = " +this.getMicropocesador().getVelocidad() + " Ghz,"                
                + "modelo= " +this.getMicropocesador().getModelo() + ","
                + "fabricante= " +this.getMicropocesador().getFabricante()
                + " } ] \n}";
    }

}

Esta clase extiende a la clase Dispositivo.java e implementa a la interfaz IComputadora por lo tanto debe implementar 10 métodos. Se han declarado 4 atributos y sus getters y setters, se ha anotado con @Override el getter del id (linea 87) porque en la clase Dispositivo.java ya se había declarado un atributo con este mismo nombre. Observa que e anotado con @Override el metodo toString() debido a que como sabes en java todos los objetos que heredan de Object por defecto ya tienen definido ese método y aquí lo sobre-escribo a mi conveniencia para mostrar el contenido de mis atributos.

TestInterfaces.java – Uso de las clases que utilizan interfaces

/*
 www.notas-programacion.com
 Descripción:
    Ejemplo con interfaces en java.
 Archivo: TestInterfaces.java
 */

package com.notasprogramacion.interfaces.test;

public class TestInterfaces {
    
    public static void main(String []args) {
        
        DiscoDuro hd = new DiscoDuro();
        hd.setId(1);
        hd.setNombre("HD Maxtor");
        hd.setModelo("PROMAX");
        hd.setFabricante("Maxtor");
        hd.setCapacidad(512);
        
        MemoriaRAM ram = new MemoriaRAM();
        ram.setId(1);
        ram.setNombre("RAM Kingston");
        ram.setModelo("NANDVER");
        ram.setFabricante("Kingston");
        ram.setCapacidad(16);
                
        Microprocesador procesador = new Microprocesador();
        procesador.setId(1);
        procesador.setNombre("AMD Athlon");
        procesador.setModelo("Athlon");
        procesador.setFabricante("AMD");
        procesador.setVelocidad(3);
                
        Computadora pc = new Computadora();
        pc.setDiscoDuro(hd);
        pc.setMemoriaRam(ram);
        pc.setMicropocesador(procesador);
        
        pc.encender();
        pc.funcionar();
        System.out.println(pc.toString());
        pc.apagar();
        
        
        System.out.println("############ USANDO REFERENCIAS A INTERFACES ############");        
        //Tambien se permite crear referencias a interfaces. Para crear una referencia a una interface se utiliza la siguiente sintaxis:
        //NombreInterfaz miRefencia = new ClaseImplementaANombreInterfaz;
        //Ejemplos:

        IMicroprocesador miProc = new Microprocesador();
        miProc.encender();
        miProc.funcionar();
        miProc.procesar();
        miProc.apagar();
        System.out.println();
                
        IDispositivoAlmacenamiento miMemoria = new MemoriaRAM();
        miMemoria.encender();
        miMemoria.funcionar();
        miMemoria.escritura();
        miMemoria.apagar();
        System.out.println();
        
        IDispositivoAlmacenamiento miHD = new DiscoDuro();
        miHD.encender();
        miHD.funcionar();
        miHD.escritura();
        miHD.apagar();
        System.out.println();
    }
}

Esta clase simplemente la escribí para ejemplificar como instanciar las clases que implementan las interfaces y como obtener la referencia de una interfaz; observa que esto se hace en el método main para poder ejecutar esta clase. La salida en Netbeans después de ejecutar la clase anterior es la siguiente:

run:

Encendiendo dispositivos...
Disco duro encendido
Memoria RAM encendida
Microprocesador encendido
Disco duro funcionando
Memoria RAM funcionando
Microprocesador funcionando
Computadora encendida...


Computadora funcionando 

Computadora{ 
[ DiscoDuro{ id = 1,nombre = HD Maxtor,capacidad = 512 GB,modelo= PROMAX,fabricante= Maxtor } ], 
[ MemoriaRAM{ id = 1,nombre = RAM Kingston,capacidad = 16 GB,modelo= NANDVER,fabricante= Kingston } ], 
[ Microprocesador{ id = 1,nombre = AMD Athlon,velocidad = 3 Ghz,modelo= Athlon,fabricante= AMD } ] 
}

Apagando dispositivos...
Disco duro apagado
Memoria RAM apagada
Microprocesador apagado
Computadora apagada.


############ USANDO REFERENCIAS A INTERFACES ############
Microprocesador encendido
Microprocesador funcionando
procesando...
Microprocesador apagado

Memoria RAM encendida
Memoria RAM funcionando
Escribiendo en Memoria RAM
Memoria RAM apagada

Disco duro encendido
Disco duro funcionando
Escribiendo en Disco duroDisco duro apagado

BUILD SUCCESSFUL (total time: 0 seconds)

Entender el concepto de interfaz es importante ya que Spring fomenta la programación orientada a interfaces. Tan es así que el Core y en general todos los módulos de Spring utilizan bastante las interfaces ya que utilizarlas se considera una buena practica de programación.

Si deseas los fuentes expuestos en este articulo los puedes bajar en un proyecto de Netbeans desde este repositorio de GitHub. En el próximo articulo haré la ultima entrega de este tema (Conceptos básicos de Java & Spring Framework) y hablare sobre las colecciones, como usarlas y porque son tan importantes para iniciar el aprendizaje de Spring.

Hasta pronto,
Saludos.

Trackbacks & Pings

Deja una respuesta

Tu dirección de correo electrónico no será publicada.