DLACZEGO INTERFEJS ??????
Zaczyna się od psa. W szczególności mops .
Mops ma różne zachowania:
public class Pug {
private String name;
public Pug(String n) { name = n; }
public String getName() { return name; }
public String bark() { return "Arf!"; }
public boolean hasCurlyTail() { return true; } }
I masz labradora, który również ma zestaw zachowań.
public class Lab {
private String name;
public Lab(String n) { name = n; }
public String getName() { return name; }
public String bark() { return "Woof!"; }
public boolean hasCurlyTail() { return false; } }
Możemy zrobić kilka mopsów i laboratoriów:
Pug pug = new Pug("Spot");
Lab lab = new Lab("Fido");
I możemy przywołać ich zachowania:
pug.bark() -> "Arf!"
lab.bark() -> "Woof!"
pug.hasCurlyTail() -> true
lab.hasCurlyTail() -> false
pug.getName() -> "Spot"
Załóżmy, że prowadzę hodowlę psów i muszę śledzić wszystkie psy, które trzymam. Muszę przechowywać moje mopsy i labradory w oddzielnych tablicach :
public class Kennel {
Pug[] pugs = new Pug[10];
Lab[] labs = new Lab[10];
public void addPug(Pug p) { ... }
public void addLab(Lab l) { ... }
public void printDogs() { // Display names of all the dogs } }
Ale to oczywiście nie jest optymalne. Jeśli chcę też pomieścić kilka pudli , muszę zmienić definicję hodowli, aby dodać tablicę pudli . Właściwie potrzebuję osobnej tablicy dla każdego rodzaju psa.
Wgląd: zarówno mopsy, jak i labradory (i pudle) są typami psów i mają ten sam zestaw zachowań. Oznacza to, że możemy powiedzieć (na potrzeby tego przykładu), że wszystkie psy mogą szczekać, mieć imię i mogą mieć lub nie mieć kręconego ogona. Możemy użyć interfejsu, aby zdefiniować, co mogą robić wszystkie psy, ale pozostawić to konkretnym typom psów, aby wdrożyły te konkretne zachowania. Interfejs mówi „oto rzeczy, które mogą robić wszystkie psy”, ale nie mówi, jak wykonywane jest każde zachowanie.
public interface Dog
{
public String bark();
public String getName();
public boolean hasCurlyTail(); }
Następnie nieznacznie zmieniam klasy Pug i Lab, aby zaimplementować zachowania Dog. Można powiedzieć, że mops to pies, a laboratorium to pies.
public class Pug implements Dog {
// the rest is the same as before }
public class Lab implements Dog {
// the rest is the same as before
}
Nadal mogę utworzyć instancję Pugs and Labs, tak jak poprzednio, ale teraz mam również nowy sposób, aby to zrobić:
Dog d1 = new Pug("Spot");
Dog d2 = new Lab("Fido");
To mówi, że d1 to nie tylko pies, to konkretnie mops. A d2 to także pies, a konkretnie laboratorium. Możemy wywołać zachowania i działają one jak poprzednio:
d1.bark() -> "Arf!"
d2.bark() -> "Woof!"
d1.hasCurlyTail() -> true
d2.hasCurlyTail() -> false
d1.getName() -> "Spot"
Tutaj opłaca się cała dodatkowa praca. Klasa Kennel stała się znacznie prostsza. Potrzebuję tylko jednej tablicy i jednej metody addDog. Oba będą działać z każdym przedmiotem, jakim jest pies; to znaczy obiekty, które implementują interfejs Dog.
public class Kennel {
Dog[] dogs = new Dog[20];
public void addDog(Dog d) { ... }
public void printDogs() {
// Display names of all the dogs } }
Oto jak go używać:
Kennel k = new Kennel();
Dog d1 = new Pug("Spot");
Dog d2 = new Lab("Fido");
k.addDog(d1);
k.addDog(d2);
k.printDogs();
Ostatnia instrukcja wyświetli: Spot Fido
Interfejs daje możliwość określenia zestawu zachowań, które będą wspólne dla wszystkich klas implementujących interfejs. W związku z tym możemy zdefiniować zmienne i kolekcje (takie jak tablice), które nie muszą z góry wiedzieć, jaki rodzaj konkretnego obiektu będą przechowywać, tylko że będą przechowywać obiekty implementujące interfejs.