Videoautomat - Videokatalog und -bestand

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.


previous Der GrundaufbauDen Videobestand anzeigen next



by Thomas Ryssel