For what it's worth ga ik hier nog wat voorbeeldjes geven. Ze zijn in Java maar in C# en andere talen is het analoog.
Het nut van interfaces is in het begin inderdaad niet echt duidelijk. Uiteindelijk stelt het ook niet veel voor: een interface is gewoon een lijst van methods. Je moet gewoon beseffen dat een klasse die een interface implementeert, ook die interface als type heeft, en dus overal gebruikt kan worden waar de code een instance van die interface verwacht.
In principe dient een interface gewoon om clientcode te ontkoppelen van een specifieke implementatie. Wat levert je dat op? Flexibiliteit.
Voorbeeld 1:
Als je een List instantieert is het beter om hem te declareren als de interface List, in plaats van als een specifiek type (tenminste als je de extra methods van ArrayList niet nodig hebt):
Code:
List<String> list = new ArrayList<String>();
in plaats van:
Code:
ArrayList<String> list = new ArrayList<String>();
Je kunt een ArrayList aan een List toekennen omdat ArrayList IS-A List (ArrayList implementeert de interface List). Dit heeft tot gevolg dat je als client op list enkel de methods kunt aanroepen die in List staan. Het nut: als je na enige profiling tot de vaststelling komt dat een ArrayList in dit geval niet performant genoeg is, kan je hem zonder problemen vervangen door een LinkedList aangezien die ook List implementeert:
Code:
List<String> list = new LinkedList<String>();
Je moet dus maar één woord vervangen en de rest van je code blijft werken zoals voorheen.
Voorbeeld 2 (gefoefeld met de generics voor de duidelijkheid):
Stel dat je een lijst van personen hebt die je wilt sorteren. Hiervoor heeft Java een algemene method Collections.sort(List list, Comparator c). list is de lijst die je wilt sorteren, c is het object dat sort() gaat vertellen hoe hij die list moet sorteren. Het object c moet van het type Comparator zijn; die interface bevat enkel een method compare(Object o1, Object o2).
Sorteren op naam doe je dan zo:
Code:
class CompareByName implements Comparator {
int compare(Person p1, Person p2) {
return p1.getName().compareTo(p2.getName()); // alfabetische volgorde
}
}
List<Person> people = new ArrayList<Person>();
...
Collections.sort(people, new CompareByName());
Sorteren op leeftijd doe je zo:
Code:
class CompareByAge implements Comparator {
int compare(Person p1, Person p2) {
if (p1.getAge() < p2.getAge())
return -1;
if (p1.getAge() > p2.getAge())
return 1;
return 0;
}
}
List<Person> people = new ArrayList<Person>();
...
Collections.sort(people, new CompareByAge()); // volgorde naar stijgende leeftijd
Je merkt op dat het voor sort() (de client) niet uitmaakt van welke klasse c precies is; de enige voorwaarde waaraan de klasse moet voldoen is dat ze Comparable implementeert.
Voorbeeld 3:
Een iterator is een object dat je de mogelijkheid biedt om alle elementen van een collection op te vragen, zonder dat je als client de implementatiedetails van die collection moet kennen. Stel dat je een algemene methode wilt schrijven die de elementen van een willekeurige collection afprint.
Je kunt aan een collection vragen om je zo een iterator terug te geven. Dat Iterator-object kan je dan gebruiken om doorheen de collection te wandelen:
Code:
void print(Iterator it) {
while (it.hasNext()) {
System.out.println(it.next());
}
}
List<Person> a = new ArrayList<Person>();
List<Person> l = new LinkedList<Person>();
Set<Person> s = new HashSet<Person>();
print(a.iterator());
print(l.iterator());
print(s.iterator());
Weer maakt het voor je print() method niet uit wat voor klasse je Iterator precies is (dat is interne keuken van de collection). De enige voorwaarde is dat de klasse de Iterator interface implementeert (met de methods next() en hasNext().
Slaapwel.