|
|
|
|
|
Für den Verleih sind Videos
unerlässlich. Dazu ist es notwendig, einen
Videokatalog zu erstellen und dem Automaten die
Möglichkeit zu geben, Videos zum Verleih anzubieten. Zum
Verwalten von Warenverzeichnissen bietet das Framework im
Paket data das Interface Catalog an. Ein Katalog besitzt
einen Namen, anhand dessen er eindeutig identifiziert werden
kann, und enthält eine bestimmte Menge von
Einträgen. Diese Einträge bestehen aus einem
Schlüsselwert, über den auf das Item zugegriffen
werden kann und aus einem dazugehörigen Wert. Dieser Wert
kann einen beliebigen Inhalt - je nach Notwendigkeit -
annehmen.
|
Catalog
|
|
Catalog wurde im Framework als
Interface implementiert, so das es in späteren
Anwendungen zum Beispiel möglich ist, auf eine Datenbank
zuzugreifen. Dazu muß dieses Interface in einer neuen
Klasse implementiert werden, welche die Daten in eine
Datenbank abbildet. Da es hier jedoch nicht um
Datenbankprogrammierung geht, wird für dieses Programm
eine schon im Framework vorhandene Implementation des Catalog -Interfaces benutzt: CatalogImpl aus dem Paket data.ooimpl .
|
CatalogImpl
|
|
Um den Katalog der Videos anzulegen, werden zunächst die
Pakete data und data.ooimpl in der Klasse
VideoMachine importiert:
|
|
|
 |  |  |
 |
import data.*;
import data.ooimpl.*;
|  |
 |  |  |
|
|
|
Dann wird der Katalog angelegt und beim Shop angemeldet. Dazu wird folgender Code in
den Anweisungsteil des Konstruktors von
VideoMachine unter super();
geschrieben:
|
|
|
 |  |  |
 |
Catalog videoCatalog = new CatalogImpl("Video-Catalog");
addCatalog(videoCatalog);
|  |
 |  |  |
|
|
|
Die erste dieser Anweisungen erstellt dabei einen neuen
Katalog mit dem Namen "Video-Catalog". Mit
der addCatalog -Anweisung wird der
gerade erzeugte Katalog in der globalen Katalogliste
angemeldet und ist dort nun unter seinem Namen
verfügbar. Katalog-Namen müssen unterscheidbar sein,
d.h. es können niemals zwei Kataloge mit dem gleichen
Namen in der globalen Katalogliste angemeldet sein.
|
|
|
Als nächstes soll der Katalog mit Videos gefüllt
werden. Dazu gehören zu jedem Video ein Name, ein
Einkaufs- und ein Verkaufspreis. Zu Demonstrationszwecken
werden daher zunächst drei Arrays angelegt, die diese
Daten enthalten. Auf diese Weise kann das eigentliche
Hinzufügen der Videos zum Katalog später sehr
einfach durch eine for -Schleife erledigt
werden. Die folgenden Zeilen werden ebenfalls direkt unter
super(); in den Konstruktor der Klasse
VideoMachine eingefügt.
|
|
|
 |  |  |
 |
String[] videos = { "Video 01", "Video 02", "Video 03", "Video 04",
"Video 05", "Video 06", "Video 07", "Video 08",
"Video 09", "Video 10" };
int[] buy = { 5000, 5000, 5000, 5000,
5000, 4000, 4000, 4000,
3000, 3000 };
int[] sell = { 4000, 4000, 4000, 4000,
3500, 3500, 3500, 3500,
3000, 3000 };
|  |
 |  |  |
|
Videosortiment
|
|
Wie man feststellt, sind alle Preise in Pfennigen
angegeben. Dies ist das im Framework verwendete Format. So
werden Fließkomma-Zahlen und die damit verbundenen
Ungenauigkeiten beim Rechnen vermieden.
|
Preise
|
|
Katalogeinträge sind durch das Interface
CatalogItem definiert. Die einzige im
Framework schon vorhandene Implementierung ist die abstrakte
Klasse CatalogItemImpl . Ein Objekt
dieser Klasse ist in der Lage, einen Namen und einen Wert vom
Typ Value zu speichern.
|
CatalogItem[Impl]
|
|
Es treten jetzt zwei Probleme auf: Zum einen ist die CatalogItemImpl abstrakt, d.h. mindestens
eine Methode wurde in dieser Klasse definiert, aber nicht
implementiert. In diesem Fall handelt es sich um die Methode
getShallowClone . Zum anderen ist in der
Klasse nur die Speicherung eines Wertes zu einem
Schlüssel im Katalog vorgesehen.
|
|
|
Um das erste Problem zu lösen wird die Klasse
VideoCassette einfach von CatalogItemImpl abgeleitet und in ihr die
Methode getShallowClone implementiert.
|
|
|
 |  |  |
 |
import data.ooimpl.*;
public class VideoCassette extends CatalogItemImpl
{
}
|  |
 |  |  |
|
|
|
Das zweite Problem ist auch nicht schwer zu beseitigen. Als
Wert wird kein einfacher Wert genommen, sondern eine Variable
vom Typ QuoteValue . QuoteValue ist eine Implementierung des
Value -Interfaces und besteht in diesem Fall aus
zwei Werten: dem Einkaufspreis und dem Verkaufspreis. Diese
müssen beim Erzeugen der Variable an den Konstruktor
übergeben werden und ebenfalls vom Typ Value sein. Als konkrete Implementierung von
Value wird hier IntegerValue verwendet.
|
QuoteValue
|
|
QuoteValue ist im Paket
data enthalten. Daher wird folgende
import -Anweisung in VideoCassette
eingefügt:
|
|
|
|
|
|
Nun benötigt VideoCassette den beschriebenen
Konstruktor. Dieser leitet lediglich die Parameter
name und value an den Konstruktor
der Oberklasse weiter.
|
|
|
 |  |  |
 |
public VideoCassette(String name, QuoteValue value)
{
super(name, value);
}
|  |
 |  |  |
|
|
|
Weiterhin soll es möglich sein, den Wert einer
VideoCassette zu verändern. Daher wird die
setValue -Methode, die in CatalogItemImpl als protected
markiert ist, überschrieben. Ein wichtiger Unterschied,
neben weniger restriktiven Zugriffsrechten ist, daß der
übergebende Parameter nun ein QuoteValue sein muß. So wird es
unmöglich, z.B. einen IntegerValue
in VideoCassette zu speichern.
|
|
|
 |  |  |
 |
public void setValue(QuoteValue value)
{
super.setValue(value);
}
|  |
 |  |  |
|
|
|
Zuletzt folgt die Methode getShallowClone , wegen der die Klasse
überhaupt erst angelegt wurde. Sie erzeugt eine Kopie der
VideoCassette mit gleichem Namen und gleichem
Wert.
|
|
|
 |  |  |
 |
protected CatalogItemImpl getShallowClone()
{
return new VideoCassette(new String(getName()),
(QuoteValue)getValue().clone());
}
|  |
 |  |  |
|
|
|
Zu beachten ist, daß beim Klonen von
Objekten auch wirklich ein neues Objekt entsteht und nicht
eine Variable, die auf des gleiche Objekt zugreift. Daher wird
in der Methode ein neuer String für den Namen erzeugt und
auch der Wert, den man über getValue erhält, geklont.
|
Klonen von Objekten
|
|
Nun wird die oben schon erwähnte
for -Schleife am Ende des Konstruktors von
VideoMachine eingefügt. In den Körper
der Schleife muß nun der Code zum Einfügen der
Katalogeinträge geschrieben werden.
|
|
|
 |  |  |
 |
for (int i=0; i < videos.length; i++) {
videoCatalog.add(new VideoCassette(
videos[i],
new QuoteValue(
new IntegerValue(buy[i]),
new IntegerValue(sell[i]))),
null);
}
|  |
 |  |  |
|
Videosortiment
|
|
Der erste Paramter der add-Anweisung ist der zum Katalog
hinzuzufügende Eintrag. Der zweite Parameter ist der zu
verwendene DataBasket , der hier nicht
benötigt wird. Wird statt des Datenkorbes
null übergeben, treten die Änderungen
sofort in Kraft. Auf die Eigenschaften und
Verwendungsmöglichkeiten eines DataBasket wird später eingegangen.
|
|
|
Nach dem Anlegen des Katalogs können
Bestände geschaffen werden. Ein Bestand
basiert immer auf einem Katalog. Ein Bestandseintrag basiert
dementsprechend auf einem Katalogeintrag aus diesem
Katalog. Daher gleichen sich auch die jeweiligen
Schlüsselwerte der Bestände/Bestandseinträge
mit denen der Kataloge/Katalogeinträge.
|
|
|
Bestände implementieren das Stock -Interface. Es gibt zwei grundlegende
Arten von Beständen: CountingStock
und StoringStock .
|
Stocks
|
|
CountingStocks verwalten zu jedem
Bestandseintrag dessen Anzahl. Sie sind daher geeignet,
Bestände zu speichern, in denen sich die jeweiligen
Artikel, die zu einem CatalogItem
gehören, nicht voneinander unterscheiden.
|
CountingStock
|
|
StoringStocks hingegen können zu
jedem eingetragenen Artikel neben seiner Zugehörigkeit zu
einem Eintrag im zugrunde liegenden Katalog noch spezielle
Merkmale speichern.
|
StoringStock
|
|
Es ist leicht ersichtlich, daß es für
"HOMECINEMA" nicht notwendig ist, jedes Video
einzeln anzusprechen. Videos eines Namens unterscheiden sich
nicht durch weitere Eigenschaften (wie z.B. die Farbe der
Hülle). Es wird also für die Anwendung ein ContingStock benutzt. Eine einfache, jedoch
hier völlig ausreichende Implementation des CountingStock -Interfaces ist CountingStockImpl . Es wird im folgenden
ein Objekt vom Typ CountingStockImpl
mit dem Namen "Video-Countingstock" und dem
zugehörigen, gerade aufgebauten Katalog
videoCatalog im Konstruktor von
VideoMachine erzeugt. Dieser wird dann zur
globalen Bestandsliste hinzugefügt.
|
CountingStockImpl
|
|
 |  |  |
 |
CountingStock cs =
new CountingStockImpl("Video-Countingstock",
(CatalogImpl)videoCatalog);
addStock(cs);
|  |
 |  |  |
|
|
|
Später wird es einen Manager geben, der vom Büro aus
den Videobestand des Automaten verwalten kann. Da er jedoch
noch nicht existiert, soll der Bestand zunächst mit Hilfe
einer Zwischenlösung aufgefüllt werden. Der nun
folgende Code wird später wieder entfernt werden:
|
|
|
 |  |  |
 |
Iterator cassettes = videoCatalog.keySet(null).iterator();
while(cassettes.hasNext()) {
cs.add((String)cassettes.next(), 5, null);
}
|  |
 |  |  |
|
|
|
Es werden von jedem im Katalog verzeichneten Video fünf
Stück in den Bestand aufgenommen. Dazu wird der add -Methode einfach der Name des
Katalogeintrags, die Anzahl der hinzuzufügenden Videos
und der zu verwendende Datenkorb (DataBasket ) übergeben. Um mit dem
Iterator arbeiten zu können, muß
java.util.* importiert werden.
|
|
|
|
|
|
Was nun noch fehlt, ist ein wenig Geld in der
Kasse. Dazu wird analog zum obigen Vorgehen zunächst ein
Katalog für die verwendeten Geldstücke und -scheine
und dann ein dazu passender Bestand erzeugt.
|
|
|
Ein spezieller Katalog für Währungen
ist im Framework eine Variable vom Typ Currency . Auch Currency ist ein Interface . Es
wird die schon vorhandene Implementation CurrencyImpl verwendet. Diese hat den
Vorteil, daß ein Katalog für Deutsche Mark nicht
mühsam aufgebaut werden muß. Vielmehr existiert ein
Konstruktor, der diese Arbeit abnimmt. Es wird im folgenden
also ein Katalog mit dem Namen "DM" für
die deutsche Währung im Konstruktor von
VideoMachine angelegt und zur globalen
Katalogliste hinzugefügt. Der Name ist dabei wirklich nur
ein Name und hat nichts mit dem erzeugten Kataloginhalt zu
tun.
|
Currency
|
|
 |  |  |
 |
addCatalog(new CurrencyImpl("DM"));
|  |
 |  |  |
|
|
|
Der zugehörige Bestand ist vom Typ MoneyBag . Ein MoneyBag ist ein spezieller CountingStock , der für die Arbeit mit
Geld gedacht ist. Auch MoneyBag ist ein
Interface und MoneyBagImpl eine
Implementation davon. Eine Variable dieses Typs soll nun der
Münzschacht des "HOMECINEMA" werden:
|
MoneyBag
|
|
 |  |  |
 |
MoneyBag coinSlot =
new MoneyBagImpl("coin slot", (CurrencyImpl)getCatalog("DM"));
|  |
 |  |  |
|
|
|
Der Konstruktor von MoneyBagImpl
benötigt, wie man sieht, ähnliche Parameter wie
CountingStockImpl : einen Namen und den
zum Bestand gehörenden Katalog. Der Katalog wurde hier
über seinen Namen mittels getCatalog aus der globalen Katalogliste
herausgesucht und an den Konstruktor übergeben.
|
|
|
Als nächstes wird das Geld zum Bestand addiert und der
Bestand zur globalen Stockliste hinzugefügt:
|
|
|
 |  |  |
 |
coinSlot.add("1-Pfennig-Stueck", 100000, null);
addStock(coinSlot);
|  |
 |  |  |
|
|
|
Wie man sieht, wird auch hier das zu addierende Geldstück
einfach durch den Namen des zugehörigen CatalogItems identifiziert. Es werden 100.000
Pfennige, also 1.000 DM, in den Münzschacht als
Wechselgeld getan. Da in diesem Programm kein Wert auf die
Verteilung der einzelnen Geldstücke gelegt wird, reicht
es einfach mit der kleinsten Einheit, also Pfennigen, zu
arbeiten.
|
|
|
Damit sind alle notwendigen Kataloge und Bestände angelegt.
|
|
|
|
Hier der Quelltext der in diesem Kapitel geänderten Klassen:
|
|
|
|
|