Im nächsten Schritt werden die Datenstrukturen für die Videos geschaffen.
Der Videokatalog
Die Videos eines Automaten zeichnen sich durch einen Titel und die jeweilige Anzahl, sowie den Einkaufspreis für den Betreiber und den Verkaufspreis für den Kunden aus. Entsprechend bietet sich zu ihrer Datenhaltung ein CountingStock
an. Ein solcher Bestand referenziert auf die Einträge des ihm zugeordneten Katalogs und speichert deren verfügbare Anzahl. Die Katalogeinträge wiederum besitzen die Attribute Bezeichnung und Preis.
Dem entsprechend wird zunächst ein Catalog
benötigt, der die Videonamen und -preise enthält. Da es sich dabei um ein Interface handelt, bedarf es einer Klasse, die dieses Schnittstellenverhalten implementiert. Im Framework existiert bereits eine vordefinierte Klasse namens CatalogImpl
, die für die meisten Zwecke ausreichen dürfte. Der Konstruktor dieser Klasse verlangt einen Bezeichner, der den Katalog eindeutig von anderen unterscheidet. Es wird zunächst folgende Zeile der Klasse VideoShop
hinzugefügt:
public class VideoShop extends Shop { public static final CatalogIdentifier<CatalogItemImpl> C_VIDEOS = new CatalogIdentifier<CatalogItemImpl>("VideoCatalog"); . . . }
Diese Konstante soll der künftige Bezeichner für den Videokatalog sein. Kataloge werden in SalesPoint (ähnlich der Java Collection API) nach den ihren Einträgen getypt. Dasselbe gilt für ihre Bezeichner. Um nicht immer die generischen Parameter mit angeben zu müssen ist es zweckmäßig eine eigene Klasse dafür anzulegen:
package videoautomat; public class VideoCatalog extends CatalogImpl<CatalogItemImpl> { public VideoCatalog(CatalogIdentifier<CatalogItemImpl> id) { super(id); } }
Der Katalog wird im Konstruktor von VideoShop
wie folgt instantiiert:
public class VideoShop extends Shop { . . . public VideoShop() { . . . addCatalog(new VideoCatalog(C_VIDEOS)); } }
Der Videokatalog ist durch die Aufnahme in die Katalogsammlung des Ladens von jeder Klasse der Anwendung aus erreichbar, jedoch ist der Aufruf, um an den Katalog zu gelangen unangenehm lang und wird vermutlich mehr als einmal verwendet. Zur Erleichterung wird eine statische Hilfsmethode in der Klasse VideoShop
geschaffen, die den Videokatalog zurückgibt.
public class VideoShop extends Shop { . . . public static VideoCatalog getVideoCatalog() { return (VideoCatalog)Shop.getTheShop().getCatalog(C_VIDEOS); } }
Nun existiert zwar ein Katalog, jedoch ohne Einträge. Damit im weiteren Verlauf des Programmierens und Testens einige Daten zur Verfügung stehen, wird die MainClass
um folgende Methode ergänzt:
public class MainClass { . . . public static void initializeVideos() { VideoCatalog videoCatalog = VideoShop.getVideoCatalog(); for (int i = 0; i < 10; i++) { String s = "Video-" + i; CatalogItemImpl video = new CatalogItemImpl(s, new QuoteValue(new IntegerValue(1500),new IntegerValue(3000))) { private static final long serialVersionUID = 8473311171089635981L; protected CatalogItemImpl getShallowClone() { return null; } }; videoCatalog.add(video, null); } } }
Die Methode bedarf ein wenig der Erklärung. Wie unschwer zu erkennen, werden in einer for-Schleife dem Videokatalog mehrere Katalogeinträge hinzugefügt. Es handelt sich bei CatalogItemImpl
um eine abstrakte Implementation des Interface CatalogItem
(und den Typ, den wir bereits bei der Festlegung des Kataloges angegeben haben). Daher muss bei der direkten Instanzierung dieser Klasse die abstrakte Methode getShallowClone()
implementiert werden. Diese Methode soll normalerweise einen echten Klon der Instanz zurückliefern. In diesem Fall wird die Methode nicht benötigt und liefert daher lediglich null
zurück. Im "richtigen" Projekt sollte die Methode aber stets korrekt implementiert werden. Das geschieht am einfachsten mit einem Copyconstructor, der zur Erzeugung einer neuen Instanz verwendet wird. Dies ist vor allem in Verbindung mit dem Bearbeiten von Katalogeinträgen wichtig. Da allerdings anonyme Klassen sich nicht selbst instanziieren können, belassen wir es hier bei der Rückgabe von null
.
Dem Konstruktor von CatalogItemImpl
muss ein String und ein Value
übergeben werden. Value
ist ein Interface und es existieren zwei Implementationen dieser Schnittstelle im Framework. Zum Einen NumberValue
, welches einen numerischen Wert kapselt und QuoteValue
, das ein Paar von Werten repräsentiert, z.B. einen Ein- und Verkaufswert. In diesem Fall wird dem Konstruktor von CatalogItemImpl
der Titel des Videos und als zweiter Parameter eine Instanz von QuoteValue
übergeben, welche wiederum mit zwei IntegerValue
erzeugt wird. IntegerValue
ist lediglich eine Spezialisierung von NumberValue
, welche einen int-Wert kapselt, der hierbei der Wert in Cent ist.
Abschließend wird in der main-Methode der MainClass
die neue Methode zur Ausführung gebracht, damit die Änderungen wirksam werden.
public class MainClass { public static void main(String arqs[]) { . . . initializeVideos(); } . . . }
Der Videobestand
Nach der Fertigstellung des Katalogs kann im Folgenden der Bestand aufgebaut werden. Wie bereits im Abschnitt Der Videokatalog erwähnt, sollen die Videos des Automaten in einem CountingStock
gespeichert werden. Auch für dieses Interface existiert eine vordefinierte Klasse mit dem gewohnten Impl
am Ende des Namens. Ein jeder Bestand bezieht sich auf einen Katalog, so dass dieser konsequenterweise neben dem String-Bezeichner dem Konstruktor von CountingStockImpl
übergeben werden muss. Ähnlich den Katalogen sind auch die Bestände nach ihren Einträgen getypt, zusätzlich aber auch noch mit den Eintragstypen des zugehörigen Katalogs. Allein aus diesem Grund lohnt es sich, eine eigene Klasse hierfür zu definieren:
package videoautomat; public class AutomatVideoStock extends CountingStockImpl<StockItemImpl, CatalogItemImpl> { public AutomatVideoStock(StockIdentifier<StockItemImpl, CatalogItemImpl> siId, Catalog<CatalogItemImpl> ciRef) { super(siId, ciRef); } }
StockItemImpl
ist dabei die Standardimplementation eines Bestandseintrages. Wir werden später noch einmal etwas genauer darauf zurückkommen. Am Anfang der Shop-Klasse muss der Identifikator für den neuen Bestand deklariert werden:
public class VideoShop extends Shop { . . . public static final StockIdentifier<StockItemImpl, CatalogItemImpl> CC_VIDEOS = new StockIdentifier<StockItemImpl, CatalogItemImpl>("VideoStock"); . . . }
Jetzt können wir den eigentlichen Stock anlegen. Dazu wird analog zum Videokatalog in den Konstruktor von VideoShop
folgende Zeile eingefügt:
public class VideoShop extends Shop { . . . public VideoShop() { . . . addStock(new AutomatVideoStock(CC_VIDEOS, getCatalog(C_VIDEOS))); } . . . }
Auch beim Videobestand lohnt es sich eine Hilfsmethode zu schreiben, die selbigen zurückliefert.
public class VideoShop extends Shop { . . . public static AutomatVideoStock getVideoStock() { return (AutomatVideoStock) Shop.getTheShop().getStock(CC_VIDEOS); } }
Der neue Bestand ist wiederum leer. Durch das Hinzufügen einer Zeile in die Initialisierungsmethode der Videos in MainClass
können dem Videobestand die benötigten Testdaten zugefügt werden.
public static void initializeVideos() { . . . AutomatVideoStock videoStock = VideoShop.getVideoStock(); for (int i = 0; i < 10; i++) { String s = "Video-" + i; . . . videoStock.add(s, 5, null); } }
Der Aufruf add(String id, int count, DataBasket db)
bewirkt, dass von dem Katalogeintrag mit der Bezeichnung id
insgesamt count
-Stück in den Bestand aufgenommen werden. Der DataBasket
, der zum Schluss übergeben wird, hat etwas mit der Sichtbarkeit der vollführten Aktion zu tun. Was es mit dem Interface DataBasket
auf sich hat, wird in Abschnitt Transaktionen mittels einer Tabelle näher erläutert. Vorerst reicht es zu wissen, dass hier durch die Übergabe von null
das Hinzufügen unmittelbar wirksam wird.
Der Grundaufbau | Den Videobestand anzeigen |