studyklar
GdI 2 · Übungsblatt 6 · Aufgabe 3

Interfaces Drucker und Scanner, Kombigerät kann beides

Ein Texteditor druckt, ein Grafikprogramm scannt. Bisher sind beide an ein bestimmtes Gerät gebunden. Mit Interfaces sagen wir nur noch, was ein Drucker oder Scanner können muss. Dann passt jedes passende Gerät, auch ein Kombigerät für beides. Rechts steht das fertige Programm, die Zeilen zum aktuellen Schritt sind hervorgehoben. Mit Weiter geht es Schritt für Schritt voran.

Die Aufgabe

Aufgabe 3

Untersuchen Sie den Code im Paket „buero“ und führen Sie die main-Methode der Klasse „BueroApp“ aus.

Der Texteditor bekommt einen Laserdrucker zugeordnet, dessen Methoden er aufruft, um etwas auszudrucken. Das Grafikprogramm bekommt einen Flachbettscanner zugeordnet, dessen Methoden es aufruft, um etwas einzuscannen.

Möchte man im Texteditor eine andere Art von Drucker nutzen, z. B. ein Objekt der Klasse „Tintenstrahldrucker“, ist das nicht so einfach möglich. Auch die Zuordnung einer – noch zu programmierenden – anderen Art von Scanner zum Grafikprogramm ist nicht ohne Weiteres möglich.

a) Ändern Sie den Code so, dass es leicht möglich ist, einem Texteditor eine andere Art von Drucker und einem Grafikprogramm eine andere Art von Scanner zuzuordnen. Definieren Sie hierfür ein Interface für Drucker und eines für Scanner. In der main-Methode soll der Texteditor nach dem Drucken auf dem Laserdrucker einen Tintenstrahldrucker zugeordnet bekommen und darauf noch einmal drucken.

b) Fügen Sie eine weitere Klasse „Kombigerät“ hinzu. Ein Kombigerät kann sowohl als Scanner als auch als Drucker genutzt werden. Weisen Sie in der main-Methode das Kombigerät sowohl dem Texteditor als Drucker als auch dem Grafikprogramm als Scanner zu und rufen Sie dessen Drucker- bzw. Scanner-Methoden auf.

Der Texteditor soll mit jedem Drucker arbeiten, das Grafikprogramm mit jedem Scanner. Dazu bekommen Drucker und Scanner je ein Interface. Danach kommt ein Gerät dazu, das beides ist.

Merke: Ein Interface (Schnittstelle) ist eine Liste von Methodenköpfen ohne Inhalt. Es sagt, was ein Gerät kann. Wie es das macht, schreibt jede Klasse selbst, die das Interface implementiert. Eine Klasse darf mehrere Interfaces implementieren.
  1. Das Problem der Ausgangslage verstehen.
  2. Interfaces Drucker und Scanner, Geräte implementieren sie.
  3. Texteditor und Grafikprogramm auf die Interfaces umstellen, testen.
  4. Das Kombigerät implementiert beide Interfaces.

Das vorgegebene Paket buero liegt uns nicht vor. Die Ausgangslage in Schritt 1 haben wir nach dem Aufgabentext nachgebaut. Die Lösung folgt der Musterlösung. Alle Klassen stehen hier in einer Datei BueroApp.java, nur BueroApp ist public.

Das Problem: der Texteditor kennt nur den Laserdrucker

class Texteditor {     private Laserdrucker drucker;     public void setDrucker(Laserdrucker drucker) {        this.drucker = drucker;    }     public void druckeText() {        drucker.reset();        drucker.drucke("xyz");    }}

So sieht der Texteditor in der Ausgangslage aus. Die Datei haben wir nachgebaut; die Nummern gelten nur für sie. Das Attribut und der Parameter von setDrucker haben den Typ Laserdrucker. Also passt dort nur ein Laserdrucker hinein.

Der Tintenstrahldrucker hat zwar auch drucke und reset. Für Java ist er aber ein ganz anderer Typ. texteditor.setDrucker(new Tintenstrahldrucker()) lässt sich darum nicht übersetzen. Der Compiler meldet: „Inkompatible Typen: Tintenstrahldrucker kann nicht in Laserdrucker konvertiert werden“.

Beim Grafikprogramm ist es genauso, nur mit dem Flachbettscanner. Gesucht ist ein gemeinsamer Typ für alle Drucker und einer für alle Scanner.

Zwei Interfaces: Drucker und Scanner

interface Drucker {     public void drucke(String s);    public void reset(); } interface Scanner {     public String scanneText();    public String scanneBild(); }

Ein Interface schreibt man mit interface statt class. Darin stehen nur Methodenköpfe mit Semikolon, ohne Rumpf. Drucker sagt: Ein Drucker kann drucke(String s) und reset(). Scanner sagt: Ein Scanner kann Text und Bild scannen und gibt das Ergebnis als String zurück.

Warum ein Interface und keine Oberklasse? Das Kombigerät in Teil b muss Drucker und Scanner sein. Eine Klasse in Java hat nur eine Oberklasse, kann aber mehrere Interfaces implementieren.

Achtung beim Namen: Java hat schon eine Klasse java.util.Scanner zum Einlesen von der Tastatur. Hier ist sie nicht importiert, darum meint Scanner unser Interface.

Aus Vorlesung 6, Folie 27 („Interfaces“): Ein Interface enthält vor allem abstrakte Methoden. Klassen implementieren es, indem sie diese Methoden schreiben. Eine Klasse kann mehrere Interfaces implementieren, und Interfaces sind Typen.
Aus Vorlesung 6, Folie 26 („Nur eine direkte Oberklasse ist möglich“): Eine Klasse mit mehreren direkten Oberklassen gibt es in Java nicht.
Noch 7 Schritte bis zum Ergebnis
Den ganzen Lösungsweg sehen Studierende und Lehrende der HS KL. Registriere dich mit deiner Adresse @stud.hs-kl.de oder @hs-kl.de, dann geht es hier direkt weiter.

Das Programm BueroApp

zwei Interfaces, vier Geräte

Abbildung 1Das Programm BueroApp

zwei Interfaces, vier Geräte

interface Drucker {     public void drucke(String s);    public void reset(); } interface Scanner {     public String scanneText();    public String scanneBild(); } class Laserdrucker implements Drucker {     @Override    public void drucke(String s) {        System.out.println("Laserdrucker druckt: " + s);    }     @Override    public void reset() {        System.out.println("Laserdrucker wird zurückgesetzt");    }} class Tintenstrahldrucker implements Drucker {     @Override    public void drucke(String s) {        System.out.println("Tintenstrahldrucker druckt: " + s);    }     @Override    public void reset() {        System.out.println("Tintenstrahldrucker wird zurückgesetzt");    }} class Flachbettscanner implements Scanner {     @Override    public String scanneText() {        String text = "abc";        System.out.println("Flachbettscanner scannt text: " + text);        return text;    }     @Override    public String scanneBild() {        String bild = "*****";        System.out.println("Flachbettscanner scannt bild: " + bild);        return bild;    }} class Kombigeraet implements Drucker, Scanner {     @Override    public String scanneText() {        String text = "abc";        System.out.println("Kombigerät scannt text: " + text);        return text;    }     @Override    public String scanneBild() {        String bild = "*****";        System.out.println("Kombigerät scannt bild: " + bild);        return bild;    }     @Override    public void drucke(String s) {        System.out.println("Kombigerät druckt: " + s);    }     @Override    public void reset() {        System.out.println("Kombigerät wird zurückgesetzt");    }} class Texteditor {     private Drucker drucker;     public void setDrucker(Drucker drucker) {        this.drucker = drucker;    }     public void druckeText() {        drucker.reset();        drucker.drucke("xyz");    }} class Grafikprogramm {     private Scanner scanner;     public void setScanner(Scanner scanner) {        this.scanner = scanner;    }     public void importiereVonScanner() {        String text = scanner.scanneText();        System.out.println(text + " importiert.");        String bild = scanner.scanneBild();        System.out.println(bild + " importiert.");    }} public class BueroApp {     public static void main(String[] args) {         Laserdrucker laserdrucker = new Laserdrucker();        Tintenstrahldrucker tintenstrahldrucker = new Tintenstrahldrucker();        Flachbettscanner flachbettscanner = new Flachbettscanner();        Kombigeraet kombigeraet = new Kombigeraet();         Texteditor texteditor = new Texteditor();        Grafikprogramm grafikprogramm = new Grafikprogramm();         texteditor.setDrucker(laserdrucker);        texteditor.druckeText();         System.out.println();         texteditor.setDrucker(tintenstrahldrucker);        texteditor.druckeText();         System.out.println();         grafikprogramm.setScanner(flachbettscanner);        grafikprogramm.importiereVonScanner();         System.out.println();         texteditor.setDrucker(kombigeraet);        texteditor.druckeText();         System.out.println();         grafikprogramm.setScanner(kombigeraet);        grafikprogramm.importiereVonScanner();    }}
LegendeDas ganze Programm.