JavaRush /Blog Java /Random-ES /Interfaces en Java

Interfaces en Java

Publicado en el grupo Random-ES
¡Hola! Hoy hablaremos de un concepto importante en Java: las interfaces. Probablemente la palabra te resulte familiar. Por ejemplo, la mayoría de los programas y juegos de computadora tienen interfaces. En un sentido amplio, una interfaz es una especie de "control remoto" que conecta dos partes que interactúan entre sí. Un ejemplo sencillo de interfaz de la vida cotidiana es el mando a distancia de un televisor. Conecta dos objetos, una persona y un televisor, y realiza diferentes tareas: subir o bajar el volumen, cambiar de canal, encender o apagar el televisor. Un lado (la persona) necesita acceder a la interfaz (presionar el botón del control remoto) para que el otro lado realice la acción. Por ejemplo, para que el televisor cambie de canal al siguiente. En este caso, el usuario no necesita conocer el dispositivo del televisor y cómo se implementa el proceso de cambio de canal en su interior. Por qué se necesitan interfaces en Java - 1Lo único a lo que el usuario tiene acceso es a la interfaz . La tarea principal es obtener el resultado deseado. ¿Qué tiene esto que ver con la programación y Java? Directo :) Crear una interfaz es muy similar a crear una clase normal, solo que en lugar de la palabra classespecificamos la palabra interface. Veamos la interfaz Java más simple y descubramos cómo funciona y para qué se necesita:
public interface Swimmable  {

     public void swim();
}
Creamos una interfaz Swimmableque puede nadar . Esto es algo así como nuestro control remoto, que tiene un “botón”: el método swim() es “nadar”. ¿ Cómo podemos utilizar este “ control remoto ”? Para ello se utiliza el método, es decir Es necesario implementar el botón en nuestro control remoto. Para utilizar una interfaz, sus métodos deben ser implementados por algunas clases de nuestro programa. Pensemos en una clase cuyos objetos se ajusten a la descripción "sabe nadar". Por ejemplo, la clase pato es adecuada Duck:
public class Duck implements Swimmable {

    public void swim() {
        System.out.println("¡Agáchate, nada!");
    }

    public static void main(String[] args) {

        Duck duck = new Duck();
        duck.swim();
    }
}
¿Qué vemos aquí? Una clase Duckse asocia con una interfaz Swimmableusando la palabra clave implements. Si recuerdas, usamos un mecanismo similar para conectar dos clases en herencia, solo que estaba la palabra " extiende ". " public class Duck implements Swimmable" se puede traducir literalmente para mayor claridad: "una clase pública Duckimplementa la interfaz Swimmable". Esto significa que una clase asociada con una interfaz debe implementar todos sus métodos. Tenga en cuenta: en nuestra clase, Duckal igual que en la interfaz , Swimmablehay un método swim()y dentro de él hay algún tipo de lógica. Este es un requisito obligatorio. Si simplemente escribiéramos " public class Duck implements Swimmable" y no creáramos un método swim()en la clase Duck, el compilador nos daría un error: Duck no es abstracto y no anula el método abstracto swim() en Swimmable ¿Por qué sucede esto? Si explicamos el error con el ejemplo de un televisor, resulta que le estamos dando a una persona un mando a distancia con el botón “cambiar canal” de un televisor que no sabe cambiar de canal. En este punto, presione el botón tantas veces como desee, nada funcionará. El mando a distancia en sí no cambia de canal: solo envía una señal al televisor, dentro de la cual se implementa un complejo proceso de cambio de canal. Lo mismo ocurre con nuestro pato: debe poder nadar para poder acceder a él mediante la interfaz Swimmable. Si no sabe cómo hacerlo, la interfaz Swimmableno conectará las dos partes: la persona y el programa. Una persona no podrá utilizar un método swim()para hacer Duckflotar un objeto dentro de un programa. Ahora has visto más claramente para qué sirven las interfaces. Una interfaz describe el comportamiento que deben tener las clases que implementan esa interfaz. "Comportamiento" es una colección de métodos. Si queremos crear varios mensajeros, la forma más sencilla de hacerlo es creando una interfaz Messenger. ¿Qué debería poder hacer cualquier mensajero? De forma simplificada, recibe y envía mensajes.
public interface Messenger{

     public void sendMessage();

     public void getMessage();
}
Y ahora podemos simplemente crear nuestras clases de mensajería implementando esta interfaz. El propio compilador nos "obligará" a implementarlos dentro de las clases. Telegrama:
public class Telegram implements Messenger {

    public void sendMessage() {

        System.out.println("¡Enviando un mensaje a Telegram!");
    }

     public void getMessage() {
         System.out.println("¡Leyendo el mensaje en Telegram!");
     }
}
WhatsApp:
public class WhatsApp implements Messenger {

    public void sendMessage() {

        System.out.println("¡Enviando un mensaje de WhatsApp!");
    }

     public void getMessage() {
         System.out.println("¡Leyendo un mensaje de WhatsApp!");
     }
}
Viber:
public class Viber implements Messenger {

    public void sendMessage() {

        System.out.println("¡Enviando un mensaje a Viber!");
    }

     public void getMessage() {
         System.out.println("¡Leyendo un mensaje en Viber!");
     }
}
¿Qué beneficios proporciona esto? El más importante de ellos es el acoplamiento flojo. Imaginemos que estamos diseñando un programa en el que recogeremos datos de clientes. La clase Clientdebe tener un campo que indique qué mensajero utiliza el cliente. Sin interfaces parecería extraño:
public class Client {

    private WhatsApp whatsApp;
    private Telegram telegram;
    private Viber viber;
}
Creamos tres campos, pero un cliente fácilmente puede tener un solo mensajero. Simplemente no sabemos cuál. Y para no quedarse sin comunicación con el cliente, hay que "introducir" todas las opciones posibles en la clase. Resulta que uno o dos de ellos siempre estarán ahí nully no son necesarios en absoluto para que el programa funcione. En su lugar, es mejor utilizar nuestra interfaz:
public class Client {

    private Messenger messenger;
}
¡Éste es un ejemplo de “acoplamiento flojo”! En lugar de especificar una clase de mensajería específica en la clase Client, simplemente mencionamos que el cliente tiene un mensajero. Cuál se determinará durante el transcurso del programa. Pero ¿por qué necesitamos interfaces para esto? ¿Por qué se agregaron al idioma? ¡La pregunta es buena y correcta! Se puede lograr el mismo resultado mediante la herencia ordinaria, ¿verdad? La clase Messengeres la clase padre, y Vibery Telegramson WhatsApplos herederos. De hecho, es posible hacerlo. Pero hay un inconveniente. Como ya sabes, no existe herencia múltiple en Java. Pero existen múltiples implementaciones de interfaces. Una clase puede implementar tantas interfaces como quiera. Imaginemos que tenemos una clase Smartphoneque tiene un campo Application: una aplicación instalada en un teléfono inteligente.
public class Smartphone {

    private Application application;
}
La aplicación y el messenger son, por supuesto, similares, pero siguen siendo cosas diferentes. Messenger puede ser tanto móvil como de escritorio, mientras que Application es una aplicación móvil. Entonces, si usáramos la herencia, no podríamos agregar un objeto Telegrama la clase Smartphone. Después de todo, una clase Telegramno puede heredar de Applicationy de Messenger! Y ya hemos logrado heredarlo Messengery agregarlo a la clase de esta forma Client. ¡Pero una clase Telegrampuede implementar fácilmente ambas interfaces! Por tanto, en una clase Clientpodemos implementar un objeto Telegramcomo Messenger, y en una clase Smartphonecomo Application. Así es como se hace:
public class Telegram implements Application, Messenger {

    //...métodos
}

public class Client {

    private Messenger messenger;

    public Client() {
        this.messenger = new Telegram();
    }
}


public class Smartphone {

    private Application application;

    public Smartphone() {
        this.application = new Telegram();
    }
}
Ahora podemos usar la clase Telegramcomo queramos. En algún lugar actuará en el papel de Application, en algún lugar en el papel de Messenger. Probablemente ya hayas notado que los métodos en las interfaces siempre están "vacíos", es decir, no tienen implementación. La razón de esto es simple: una interfaz describe el comportamiento, no lo implementa. “Todos los objetos de las clases que implementan la interfaz Swimmabledeben poder flotar”: eso es todo lo que nos dice la interfaz. Cómo nadará exactamente un pez, un pato o un caballo es una pregunta para las clases Fish, Ducky Horse, y no para la interfaz. Al igual que cambiar de canal es tarea de un televisor. El control remoto simplemente te da un botón para hacerlo. Sin embargo, Java8 tiene una adición interesante: los métodos predeterminados. Por ejemplo, su interfaz tiene 10 métodos. 9 de ellos se implementan de manera diferente en diferentes clases, pero uno se implementa igual en todas. Anteriormente, antes del lanzamiento de Java8, los métodos dentro de las interfaces no tenían ninguna implementación: el compilador arrojaba inmediatamente un error. Ahora puedes hacerlo así:
public interface Swimmable {

   public default void swim() {
       System.out.println("¡Nadar!");
   }

   public void eat();

   public void run();
}
Usando la palabra clave default, hemos creado un método en la interfaz con una implementación predeterminada. Necesitaremos implementar los otros dos métodos eat()y run()nosotros mismos en todas las clases que implementarán Swimmable. No es necesario hacer esto con el método swim(): la implementación será la misma en todas las clases. Por cierto, te has encontrado con interfaces más de una vez en tareas pasadas, aunque ni siquiera te diste cuenta :) Aquí tienes un ejemplo obvio: ¡ ¿Por qué necesitamos interfaces en Java? - 2Trabajaste con interfaces Listy Set! Más precisamente, con sus implementaciones: ArrayList, LinkedListy HashSetotras. El mismo diagrama muestra un ejemplo cuando una clase implementa varias interfaces a la vez. Por ejemplo, LinkedListimplementa las interfaces Listy Deque(cola de doble cara). También está familiarizado con la interfaz Map, o mejor dicho, con sus implementaciones HashMap. Por cierto, en este diagrama puedes ver una característica: las interfaces se pueden heredar entre sí. La interfaz SortedMapse hereda de Mapy Dequese hereda de la cola Queue. Esto es necesario si desea mostrar la conexión entre interfaces, pero una interfaz es una versión extendida de otra. Veamos un ejemplo con una interfaz Queue: una cola. Aún no hemos repasado las colecciones Queue, pero son bastante sencillas y están dispuestas como una fila normal en una tienda. Puede agregar elementos solo al final de la cola y quitarlos solo desde el principio. En cierto momento, los desarrolladores necesitaban una versión ampliada de la cola para poder agregar y recibir elementos de ambos lados. Así se creó una interfaz Deque: una cola bidireccional. Contiene todos los métodos de una cola normal, porque es el "padre" de una cola bidireccional, pero se han agregado nuevos métodos.
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION