Informatik

Filter als Klassen

Du hast jetzt ein Dutzend Filter geschrieben, und alle stehen als Methoden nebeneinander in Main.java. Das funktioniert, hat aber zwei Schwächen.

Zum einen bekommt jeder Filter seine Einstellungen als Parameter mitgereicht – schwelle(grau, 128), heller(grau, 60). Eine Liste von Filtern lässt sich so nicht bilden, weil jeder anders aufgerufen wird.

Zum anderen wird das Hintereinanderschalten unübersichtlich, sobald es mehr als zwei sind:

leinwand.zeige(schwelle(kanten(weich(heller(grau, 30))), 40));

Das liest sich von innen nach außen, also gegen die Reihenfolge, in der es passiert. Beides lösen wir jetzt mit dem, was du über Vererbung und abstrakte Klassen gelernt hast.

Ein Filter wird ein Objekt

Alle Filter haben eines gemeinsam: Sie machen aus einem Gitter ein neues. Das ist die gemeinsame Schnittstelle, und mehr braucht die Oberklasse nicht.

public abstract class Filter {
    public abstract int[][] anwenden(int[][] pBild);
}

Was ein Filter darüber hinaus braucht – eine Grenze, eine Anzahl Stufen –, speichert er in eigenen Attributen und bekommt es im Konstruktor.

Öffne im Programmierbereich nacheinander Filter.java, Heller.java, Invertieren.java und Schwelle.java. Der Rechenteil in jedem anwenden ist derselbe, den du schon geschrieben hast – nur steht er jetzt in einer eigenen Klasse, und die Einstellung kommt aus einem Attribut statt aus einem Parameter.

Drei Dinge sind hier passiert:

  1. Die Einstellung wandert ins Objekt. new Schwelle(128) merkt sich die Grenze. Danach sieht der Aufruf bei jedem Filter gleich aus: f.anwenden(bild).
  2. Gemeinsames wandert in die Oberklasse. leeresWie und begrenzt stehen einmal in Filter statt fünfmal in den Unterklassen. Sie sind protected, gehören also den Unterklassen, aber nicht der Außenwelt.
  3. Der Typ ist Filter, das Objekt ist eine Unterklasse. In der Zeile Filter aufhellen = new Heller(60); stehen beide. Welches anwenden ausgeführt wird, entscheidet sich erst zur Laufzeit – das ist Polymorphie.

In der Online-IDE wird @Override vor der überschreibenden Methode nicht verwendet. In echtem Java gehört es dorthin; es ändert nichts am Ablauf, lässt den Übersetzer aber prüfen, ob wirklich etwas überschrieben wird.

Aufgabe 1: Die Filterkette

Jetzt zahlt sich die gemeinsame Oberklasse aus: Filter lassen sich in ein Feld legen und der Reihe nach anwenden.

Ergänze im Hauptprogramm die Methode

int[][] kette(Filter[] pFilter, int[][] pBild)

Sie wendet die Filter in der Reihenfolge des Feldes an und liefert das Ergebnis. Erprobt wird sie mit

Filter[] scherenschnitt = { new Weichzeichnen(), new Kanten(), new Schwelle(40) };

Die Klassen Weichzeichnen und Kanten liegen im Programmierbereich als leere Hüllen bereit. Ihr Rechenteil steht schon fertig auf den Seiten Weichzeichnen und Kanten finden – du musst ihn nur noch in die Form einer Klasse bringen.

Tipp 1: Die Schleife

Die Kette braucht eine Variable, die das Zwischenergebnis hält. Am Anfang ist das das Ausgangsbild, danach jedes Mal das Ergebnis des letzten Filters.

Tipp 2: Woher kommt der Typ?

pFilter[i] hat den Typ Filter, und Filter kennt anwenden. Mehr musst du nicht wissen – ob dort ein Schwelle- oder ein Kanten-Objekt steckt, geht die Kette nichts an. Genau das ist der Gewinn.

Eine mögliche Lösung. Erfrage das Passwort bei deiner Lehrkraft oder sieh auf der Seite Lösungspasswörter nach.

Aufgabe 2: Ein Filter, der Filter enthält

Die Unscharfmaskierung von der Seite Weichzeichnen braucht selbst einen Weichzeichner. Als Klasse geschrieben, enthält sie also einen anderen Filter als Attribut.

a) Fülle die Klasse Schaerfen im Programmierbereich aus. Sie legt sich im Konstruktor ein Weichzeichnen-Objekt an und benutzt es in anwenden.

b) Gib ihr einen zweiten Konstruktor, dem man den inneren Filter übergeben kann. Was gewinnst du damit?

c) Warum ist das keine Vererbung? Beschreibe in einem Satz den Unterschied zwischen „Schaerfen ist ein Filter" und „Schaerfen hat einen Filter". Beides trifft hier zu.

Eine mögliche Lösung. Erfrage das Passwort bei deiner Lehrkraft oder sieh auf der Seite Lösungspasswörter nach.

Zum Weiterdenken

In Aufgabe 1 steht die Kette als Methode im Hauptprogramm. Schreibe sie als Klasse Kette, die selbst von Filter erbt und im Konstruktor ein Filter[] bekommt.

a) Was kannst du danach, was vorher nicht ging? Denk an Aufgabe 2.

b) Kann eine Kette eine andere Kette enthalten? Was bedeutet das für die Tiefe, in der Filter geschachtelt werden können?

c) Dieses Muster – eine Klasse, die dieselbe Schnittstelle erfüllt wie die Dinge, die sie enthält – hat einen Namen. Such ihn und schau dir an, wo es sonst noch vorkommt. Dateiordner und Dateien sind ein bekanntes Beispiel.

Filter als Klassen

Teilbare URL erstellen

Abschnitte auswählen