18. Rekursion Inhaltsverzeichnis 20. Funktionale Abstraktion

19. Persistenz

Die Schnittstelle der Warteschlange kann um weitere Methoden erweitert werden, die der Warteschlange Persistenz[1] verleihen:

/** Persistent Queue - PersQ.scala */

trait PersQ[E] extends Queue[E] {

   /** Stores the content of the queue into a file.

   * The queue remains unchanged.

   * @throws IllegalStateException if saving not possible. */

   def save(filename: String)

   /** Loads the content of the queue from a file.

   * The old content gets lost.

   * Loaded queue not necessarily equals the saved one */

   def load(filename: String): PersQ[E] }

Unterschiedliche Implementierungen dieser Schnittstelle sind geeignet, die Ein/Aus­ga­betechniken von Java und Scala zu demonstrieren. Die einfachste ist ein Textstrom mit Hilfe von java.io.Reader/Writer:

/** Implementation of persistence with text file - PersArrayQ.scala

 *  Assumes presence of implicit conversion from String to E */

import java.io._

class PersArrayQ[E](size: Int) extends ArrayQ[E](size) with PersQ[E] {

   def save(filename: String) = {

     val bw = new BufferedWriter(new FileWriter(filename))

     for (i <- 0 until this.anzahl) {

        bw.write(inhalt((ältestes + i) % inhalt.length).toString)

        bw.newLine }

      bw.close }

   def load(filename: String) = {

     this.clear

     val br = new BufferedReader(new FileReader(filename))   

     var zeile = br.readLine

     while (zeile != null || zeile.length != 0) {

        this.add(zeile.asInstanceOf[E])

        zeile = br.readLine } } }

Bei dieser Lösung schreiben wir die Elemente vom Typ E in eine Textdatei, indem wir ihren Inhalt mit toString in ein String konvertieren. Die Frage ist, wie beim Zurücklesen hieraus ein Objekt vom Typ E wiederhergestellt wird. Die obige Lösung mit asInstanceOf[E] setzt implizite Konvertierung von der Klasse des aktuellen Typparameters nach String voraus.

Ein Binärstrom (mit Hilfe von java.io.Object­In/Output­Stream) zeigt, wie eine komplexe Datenstruktur mit einem einzigen Methodenaufruf (writeObject und readObject) in einen Strom (so auch in eine Datei) geschrieben und von dort wiederhergestellt kann. Objektdiagramme stellen dabei die Verkettung von Strömen dar (s. Abbildung 14):

/** Implementation of persistence with binary file - PersListQ.scala */

// does not work

import java.io._

class PersListQ[E] extends ListQ[E] with PersQ[E]

     with java.io.Serializable {

   def save(filename: String) = {

     new ObjectOutputStream(new FileOutputStream(filename)).

        writeObject(this) }

   def load(filename: String) = {

     val plq = new ObjectInputStream(new FileInputStream(filename)).

        readObject().asInstanceOf[PersListQ[E]]

     this.ältester = plq.ältester

     this.jüngster = plq.jüngster } }

Diese Lösung funktioniert allerdings nur dann, wenn PersListQ und der aktuelle Typparameter (für E) parameterlose Konstruktore besitzen, sowie wenn die Klassen beim Aufruf von load präsent sind. Bei PersArrayQ (mit Klassenparameter size) mit dieser Technik würde readObject nicht wissen, wie große Reihung erzeugt werden soll.

Das recht komplexe Zusammenspiel der Stromklassen und Objekte kann mit einem Objektdiagramm gemeinverständlich dargestellt werden. Das Klassendiagramm wird jedoch nicht viel komplexer:

Abbildung 40: Klassendiagramm mit PersQ

18. Rekursion Inhaltsverzeichnis 20. Funktionale Abstraktion

[1] Dauerhaftigkeit: Nach der Beendigung des Programms kann der Inhalt wiederhergestellt werden


Version: 5. Dezember 2010

© Prof. Solymosi, 2010, Beuth-Hochschule für Technik Berlin