Apache Groovy #9 – objektorientierte Programmierung – Interfaces

In diesem Beitrag stelle ich dir vor, wie du Interfaces in Groovy implementieren und nutzen kannst.

Im ersten Teil zur objektorientierten Programmierung mit Groovy habe ich dir bereits gezeigt, wie du Klassen und abstrakte Klassen erstellen und somit mit Vererbung arbeiten kannst. Hier soll es nun um die Interfaces gehen.

In diesem Beitrag verwende ich die Eclipse IDE welche ich für die Entwicklung von Groovy Skripte erweitert habe, wie du dieses machen kannst, habe ich im Beitrag Einrichten von Eclipse zum Entwickeln in Apache Groovy ausführlich erläutert.

Was ist ein Interface?

Ein Interface definiert eine Art Muster, welchem eine Klasse entsprechen muss, die dieses Interface implementiert. D.h. es werden die Methoden definiert, aber nicht ausprogrammiert. Die eigentliche Bussiness-Logik wird in den Klassen oder Serviceimplementationen geschrieben.

Auf der Seite https://docs.groovy-lang.org/docs/next/html/documentation/#interfaces findest du die offizielle Dokumentation zu den Interfaces in Apache Groovy.

Wie wird ein Interface aufgebaut?

Ein Interface wird eingeleitet mit dem Schlüsselwort „interface“ gefolgt von einem Namen.

interface ReportService

Ein Interface kann weitere Interfaces erweitern, dafür werden diese mit dem Schlüsselwort „extends“ Kommasepariert aufgeführt.

interface ReportService<T> extends Serializable, SQLData 

ein kleines Beispiel

Starten wir mit einem kleinen Beispiel, zunächst wollen wir einen Service schreiben, welcher nur eine Funktion bietet, der Ausgabe einer Zeile auf der Kommandozeile.

interface OutputService {
	def void printlnWithTimestamp(String text)
}

Die Implementation des Services kann dann wiefolgt aussehen:

import java.text.SimpleDateFormat

class OutputServiceImpl implements OutputService{

	@Override
	public void printlnWithTimestamp(String text) {
		SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:SS")
		String datetime = df.format(new Date())
		println("["+datetime+"] "+text)		
	}
}

Wenn wir dieses nun wie folgt initialisieren und aufrufen:

OutputService outputService

outputService = new OutputServiceImpl()
outputService.printlnWithTimestamp("Hallo Welt!")

Dann erhalten wir folgende Ausgabe auf der Kommandozeile / im Terminal der IDE:

Ausgabe einer Servieimplementation in Groovy
Ausgabe einer Servieimplementation in Groovy

Erweitern des Groovy Interfaces um eine Methode

Wenn wir nun das Interface um eine weitere Methode erweitern, dann werden im gleichen Zuge gezwungen diese auch in der Implementierung zu programmieren. Dieses ist ein Vorteil bei Interfaces und auch abstrakten Klassen, denn so zwingt man andere Entwickler sich an das Format zu halten.

Eine weitere Implementierung

Natürlich kann man auch eine weitere Implementierung zu diesem Interface schreiben und aufrufen und so zwischen mehreren Funktionen mit dem gleichen Namen wechseln.

In meinem Fall erstelle ich mir eine weitere Implementation mit dem Zusatz das, dass Datumsformat auf Deutsch und zusätzlich der Benutzername ausgegeben wird.

import java.text.SimpleDateFormat

class OutputServiceImpl2 implements OutputService{

	@Override
	public void printlnWithTimestamp(String text) {
		SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy HH:mm:SS")
		String datetime = df.format(new Date())
		
		String username = System.getProperty("user.name");
		
		println("["+datetime+", "+username+"] "+text)		
		
	}
}

Wenn wir dieses nun initialisieren und ausführen, so erhalten wir nachfolgende Ausgabe:

eine weitere Implementation des Interfaces
eine weitere Implementation des Interfaces

Erkennbar ist, dass wir in der Zeile 2 unser Interface definieren und jeweils in den Zeilen 4 & 7 eine andere Implementation zuweisen. Dieses funktioniert, da wir für unsere Klassen eine Vorlage nutzen und somit mit dieser arbeiten.

Groovy-Interface-Magic

Kommen wir nun zur Groovy Magic mit Interfaces. Wenn wir eine „normale“ Klasse mit den Methoden aus dem Interface implementieren, ohne das Interface selber zu implementieren, dann können wir eine Instanz von dieser Klasse in das Interface umwandeln.

import java.text.SimpleDateFormat

public class OutputClass {
	
	public void printlnWithTimestamp(String text) {
		SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:SS")
		String datetime = df.format(new Date())
		println("["+datetime+"] "+text)
	}

	public void eineWeitereMethode() {
		println("Hier passiert nichts!")
	}
}

Um nun diese Klasse in eine Instanz unseres Interfaces zu verwandeln, benötigen wir den coercion operator, mit diesem können wir diverse Datentypen umwandeln (ähnlich wie ein casting).

OutputClass outputClass = new OutputClass()
service = outputClass as OutputService
assert service instanceof OutputService

Wenn wir dieses nun aufrufen, dann wird keine Fehlermeldung ausgegeben und unsere Klasse verhält sich wie das Interface. Jedoch verlieren wir die Funktion „eineWeitereMethode“, denn diese ist im Interface nicht definiert.

Kommentar hinterlassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert