und die Aufgabenstellung als Info :
Validierung der Eingaben und Exceptions im Fehlerfall
Insbesondere bei der Eingabe von Daten in Programme passieren häufig Fehler, die zu Situationen führen, in denen ein Wert beim Aufruf einer Methode oder der Erzeugung eines neuen Objekts einen Wert besitzt, den das Programm nicht verarbeiten kann. Deshalb ist es wichtig, bei öffentlichen Schnittstellen die beim Aufruf einer Methode angegebenen Werte auf Korrektheit zu prüfen.
Validieren Sie IMMER die Eingaben der angegebenen Methoden und Konstruktoren und werfen Sie im Fehlerfall eine passende Exception. Es sollen folgende Konventionen gelten:
Wird anstatt eines Objektes der Wert null übergeben, so ist eine java.lang.NullPointerException zu werfen.
Handelt es sich bei dem Objekt um einen String und ist dieser leer, also : "" , dann soll eine de.uniwue.jpp.accountbook.EmptyStringException geworfen werden.
Lesen Sie die Aufgabenstellung sorgfältig, an einigen Stellen kann von diesen Regeln abgewichen werden.
Wirf eine Methode eine eigene Exception, so wird der vollqualifizierte Klassenname angegeben. Implementieren Sie in diesem Fall die Exception. Leiten Sie diese stets von java.lang.RuntimeException ab.
Legen Sie die Klasse de.uniwue.jpp.accountbook.EmptyStringException an. Sie soll von java.lang.RuntimeException erben und alle Konstruktoren der Mutterklasse bereitstellen.
Die Klasse Account
Ein Account steht für ein beliebiges Konto, z.B. Sparbuch, Girokonto, Bargeldbestand, ... . Um Sie unterscheiden zu können, hat jeder Account einen eindeutigen Namen. Außerdem wird der Eröffnungsstand (opening balance) registriert. Implementieren Sie zuerst die Klasse Account im Paket de.uniwue.jpp.accountbook.model,
Die Klasse besitzt die Felder:
String name
Der eindeutige Name des Account.
float openingBalance
Der Eröffnungsstand des Account.
und folgende Konstruktoren und Methoden:
public Account(String name, float openingbalance)
Erstellt einen neuen Account und setzt seinen Namen und Eröffnungsstand. Validieren Sie die Parameter des Konstruktors. Folgende Fälle sollten zu einer Ausnahme führen:
<name> hat den Wert: null
Es wird eine java.lang.NullPointerException geworfen.
<name> ist der leere String.
Es wird eine de.uniwue.jpp.accountbook.model.EmptyStringException geworfen. Erstellen Sie hierzu die von java.lang.RuntimeException abgeleitete Exception de.uniwue.jpp.accountbook.model.EmptyStringException.
public String getName()
Liefert den Namen des Accounts.
public float getOpeningBalance()
Liefert den Eröffnungsstand des Account.
public boolean equals(Object obj) / public int hashCode()
Überschreiben Sie die Methoden equals/hashCode so, dass zwei Account-Objekte genau dann gleich sind, wenn ihre Namen übereinstimmen. Achten Sie auf die Einhaltung des Vertrags zwischen equals/hashCode
public String toString()
Überschreiben Sie die Methode so, dass ein String der Form
[<name> (<openingbalance>)]
zurückgegeben wird.
Die Klasse Category
Buchungen im Haushaltsbuch sollen Kategorien zugeordnet werden. Mögliche Kategorien sind z.B. Lebensmittel, Miete, Abonnements, ... . Dabei können Kategorien Hierarchien bilden:
|--Lebensmittel
\-- Getränke
\-- Fleisch
\-- Gemüse
\-- Sonstiges
Implementieren Sie als nächstes die Klasse de.uniwue.jpp.accountbook.model.Category. Die Klasse besitzt die Eigenschaften:
UUID uuid
Ein Universally Unique Identifier. Benutzen Sie hierzu den Typ java.util.UUID.
name: String
Der Name der Kategorie.
description: String
Eine Beschreibung der Kategorie.
parent: Category
Die Oberkategorie, zu der diese Kategorie gehört.
categories: Set<Category>
Eine Menge von Unterkategorien.
und folgende Konstruktoren und Methoden:
public Category(String uuid, String name, String description, Category parent)
Erstellt ein neues Category Objekt mit den gegebenen Werten und setzt die UUID auf den gegeben Wert. Das Argument parent darf den Wert <null> annehmen.
public Category(String name, String description, Category parent)
Erstellt ein neues Category Objekt mit den gegebenen Werten und setzt eine zufällige UUID. Das Argument parent darf den Wert <null> annehmen.
public String getName()
Liefert den Namen der Kategorie.
public void addCategory(Category category)
Fügt eine neue Unterkategorie hinzu. Ist die Kategorie bereits vorhanden, soll Sie nicht erneut hinzugefügt werden. Achten Sie darauf, die Eigenschaft parent in der Unterkategorie korrekt zu setzen.
public Set<Category> getCategories()
Liefert die Menge von Unterkategorien.
public String getDescription()
Liefert die Beschreibung der Kategorie.
public Category getParent()
Liefert die Oberkategorie dieser Kategorie oder den Wert null, falls die Kategorie zu keiner Oberkategorie gehört.
public UUID getUuid()
Liefert die eindeutige UUID für die Kategorie.
public boolean equals(Object o) / public int hashCode()
Überschreiben Sie equals und hashCode so, dass zwei Category Objekte genau dann gleich sind, wenn ihre uuid's gleich sind. Achten Sie auf die Einhaltung des Vertrags zwischen equals/hashCode
public String toString()
Überschreiben Sie die Methode so, dass ein String der Form
[<name> (<uuid>)]
zurückgegeben wird.
Die Klasse Entry
Die Klasse Entry repräsentiert einen Eintrag in das Haushaltsbuch. Ein Eintrag erfolgt immer in einer bestimmten Kategorie und wird außerdem einem Konto zugeordnet, sodass die Geldein- und abgänge nachvollzogenwerden können.
Implementieren Sie die Klasse de.uniwue.jpp.accountbook.model.Entry. Die Klasse hat mindestens die Felder:
Category category
Die Kategorie, zu der der Eintrag zugeordnet wird.
Account account
Das Konto, dem der Eintrag zugeordnet wird.
String description
Die Beschreibung des Eintrags.
Calendar timestamp
Das Datum, an dem die Position erzeugt wurde.
float value
Der Wert des Eintrages in Euro.
und außerdem mindestens die folgenden Konstruktoren und Methoden:
public Entry(Category category, Account account, Calendar timestamp, String description, float value)
Initialisiert einen Eintrag.
public Calendar getTimestamp()
Liefert das Datum, an dem die Position erzeugt wurde.
public String getDescription()
Liefert die Beschreibung des Eintrags.
public float getValue()
Liefert den Wert des Eintrags.
public Category getCategory()
Liefert die Kategorie, der der Eintrag zugeordnet ist.
public Account getAccount()
Liefert den Account, dem der Eintrag zugeordnet ist.
public boolean equals(Object o) / public int hashCode()
Überschreiben Sie equals und hashCode so, dass zwei Entry Objekte genau dann gleich sind, wenn description, value und timestamp gleich sind. Vergleichen Sie bei timestamp nur die Felder für Jahr, Monat und Tag.Achten Sie auf die Einhaltung des Vertrags zwischen equals/hashCode
public String toString()
Überschreiben Sie die Methode toString() so, dass Sie einen String der Form:
[<TT.MM.YYYY> - <value> - <description>]
zurück gibt. Benutzen Sie zur Formatierung des Datums die Klasse java.text.SimpleDateFormat.
Filter für Einträge
Es existieren bereits Konten, Kategorien und Einträge, die als Modell für unser Haushaltsbuch dienen. Um Auswertungen vornehmen zu können, ist es wichtig, die Menge aller Einträge auf bestimmte Eigenschaften hin zu Filtern. Beispiele dafür sind:
Einname- / Ausgabestatistik für spezielle Zeiträume
Einträge einzelner Kategorien, oder Mengen von Kategorien
Einträge für eine Auswahl von Konten
...
Außerdem kann es noch interessant sein, verschiedene Filter miteinander logisch zu verbinden.
Legen Sie die Schnittstelle (Interface) de.uniwue.jpp.accountbook.filter.Filter mit folgendem Inhalt an:
package de.uniwue.jpp.accountbook.filter;
import de.uniwue.jpp.accountbook.model.Entry;
/**
* An interface for arbitrary filters that can be applied to a collection of Entries.
*/
public interface Filter {
/**
* Applies this filter to an {@link Entry} instance.
*
* @param entry an entry.
* @return true if the filter is successfully applied, false otherwise.
*/
boolean apply(Entry entry);
}
Konkrete Filter
InCategoryFilter
Die Methode Filter.apply(Entry entry) liefert genau dann <true>, wenn der Eintrag einer der im Filter definierten Kategorien angehört. Erstellen Sie die von de.uniwue.jpp.accountbook.filter.Filter abgeleitete Klasse de.uniwue.jpp.accountbook.filter.InCategoryFilter mit folgendem Konstruktor:
public InCategoryFilter(Collection<Category> categories)
Initialisiert den Filter mit einer Liste von Kategorien, die er akzeptiert.
InMonthFilter
Die Methode Filter.apply(Entry entry) liefert genau dann <true>, wenn der Eintrag in dem im Filter angegebenen Monat und Jahr erstellt wurde. Zur Angabe des Monats werden die Konstanten aus java.util.Calendar verwendet. Erstellen Sie die von de.uniwue.jpp.accountbook.filter.Filter abgeleitete Klasse de.uniwue.jpp.accountbook.filter.InMonthFilter mit folgendem Konstruktor:
public InMonthFilter(int month, int year)
Initialisiert den Filter mit einem Monat und Jahr, für die Einträge akzeptiert werden sollen.
Logische Verknüpfungen zwischen Filtern
Filter können miteinander logisch verknüpft werden. Es ist zum Beispiel denkbar, dass man nach dem Monat und der Kategorie filtern möchte. Hierzu sollen für die logischen Verknpüfungen and, or, not Klassen bereitgestellt werden, die Filter miteinander verknüpfen und somit komplexe Filterregeln erlauben. Die folgenden Klassen werden ebenfalls von de.uniwue.jpp.accountbook.filter.Filter abgeleitet und ihre apply-Methode entsprechend der Beschreibung implementiert.
NotFilter
Erstellen Sie die Klasse de.uniwue.jpp.accountbook.filter.NotFilter mit dem Konstruktor:
public NotFilter(Filter filter)
Erzeugt eine Instanz mit dem gegebenen Filter.
Implementieren Sie die apply-Methode so, dass Sie das Ergebnis des im Konstruktor gesetzten Filter negiert.
AndFilter
Erstellen Sie die Klasse de.uniwue.jpp.accountbook.filter.AndFilter mit dem Konstruktor:
public AndFilter(Filter left, Filter right)
Erzeugt eine Instanz mit den gegebenen Filtern.
Implementieren Sie die apply-Methode so, dass Sie genau dann <true> liefert, wenn die Anwendung der beiden gesetzten Filter <true> ergibt. Sonst gibt sie <false> zurück.
OrFilter
Erstellen Sie die Klasse de.uniwue.jpp.accountbook.filter.OrFilter mit dem Konstruktor:
public OrFilter(Filter left, Filter right)
Erzeugt eine Instanz mit den gegebenen Filtern.
Implementieren Sie die apply-Methode so, dass Sie genau dann <false> liefert, wenn die Anwendung der beiden gesetzten Filter <false> ergeben. Sonst gibt sie <true> zurück.
Die Klasse AccountBook
Die Klasse AccountBook verwaltet Kategorien, Konten und Einträge. Bei Kategorien wird noch zwischen Ausgaben (expenses) und Einnahmen (incomes) unterschieden. Außerdem bietet Sie Methoden zum Zugriff und Filtern für Kategorien und Einträge. Dies wird für die spätere Auswertung benötigt.
Implementieren Sie die Klasse de.uniwue.jpp.accountbook.model.AccountBook. Wählen Sie für die Verwaltung der Konten, Einträge und Kategorien eine geeignete Implementierung von java.util.Collection. Die Klasse hat mindestens die Felder:
Collection<Account> accounts
Eine Sammlung von Konten.
Collection<Category> incomes
Eine Sammlung von Kategorien, in denen Einnahmen verbucht werden.
Collection<Category> expenses
Eine Sammlung von Kategorien, in denen Ausgaben verbucht werden.
Collection<Entry> entries
Eine Sammlung von Einträgen.
und außerdem die folgenden Konstruktoren und Methoden:
public AccountBook()
Initialisiert ein leeres Haushaltsbuch.
public Collection<Account> getAccounts()
Liefert eine Sammlung mit allen registrierten Konten. Achten Sie darauf, dass es nicht möglich ist, über die zurückgegebene Menge den internen Zustand der Klasse AccountBook zu verändern.
public Collection<Category> getIncomes()
Liefert eine Sammlung mit allen Einnahmekategorien. Achten Sie darauf, dass es nicht möglich ist, über die zurückgegebene Menge den internen Zustand der Klasse AccountBook zu verändern.
public Collection<Category> getExpenses()
Liefert eine Sammlung mit allen Ausgabekategorien. Achten Sie darauf, dass es nicht möglich ist, über die zurückgegebene Menge den internen Zustand der Klasse AccountBook zu verändern.
public Collection<Entry> getEntries()
Liefert eine Sammlung mit allen Einträgen. Achten Sie darauf, dass es nicht möglich ist, über die zurückgegebene Menge den internen Zustand der Klasse AccountBook zu verändern.
public void addAccount(Account account)
Fügt einen neuen Account zur Sammlung hinzu, falls dieser noch nicht existiert.
public void addIncomeCategory(Category category)
Fügt eine neue Einnahmekategorie zur Sammlung hinzu, falls diese noch nicht existiert.
public void addExpenseCategory(Category category)
Fügt eine neue Ausgabekategorie zur Sammlung hinzu, falls diese noch nicht existiert.
public void addEntry(Entry entry)
Fügt einen neuen Eintrag zur Sammlung hinzu, falls dieser noch nicht existiert.
public Collection<Category> findAllExpenseCategories()
Erstellt eine flache Repräsentation der Kategorienhierarchie für Ausgaben. Jede Kategorie taucht genau einmal in der Sammlung auf.
Beispiel:
-- Lebensmittel
\-- Getränke
\-- Fleisch
-- Versicherungen
wird zu:
[Lebensmittel, Getränke, Fleisch, Versicherungen]
public Collection<Category> findAllIncomeCategories()
Erstellt eine flache Repräsentation der Kategorienhierarchie für Einnahmen. Jede Kategorie taucht genau einmal in der Sammlung auf.
Beispiel:
-- Lebensmittel
\-- Getränke
\-- Fleisch
-- Versicherungen
wird zu:
[Lebensmittel, Getränke, Fleisch, Versicherungen]
public Collection<List<Category>> findExpenseCategoryByName(String name)
Findet alle Ausgabenkategorien mit dem angegeben Namen und liefert eine Liste mit Pfaden zu den jeweiligen Kategorien.
Beispiel:
-- Lebensmittel
\-- Getränke
\-- Fleisch
-- Party
\-- Getränke
Der Aufruf mit name = "Getränke" liefert dann
[[Lebensmittel, Getränke], [Party, Getränke]]
public Collection<List<Category>> findIncomeCategoryByName(String name)
Findet alle Einnahmenkategorien mit dem angegeben Namen und liefert eine Liste mit Pfaden zu den jeweiligen Kategorien.
Beispiel:
-- Lebensmittel
\-- Getränke
\-- Fleisch
-- Party
\-- Getränke
Der Aufruf mit name = "Getränke" liefert dann
[[Lebensmittel, Getränke], [Party, Getränke]]
public Account findAccountByName(String name)
Findet ein Konto mit dem angegebenen Namen. Ist kein Konto mit diesem Namen vorhanden, wird eine de.uniwue.jpp.accountbook.model.AccountNotFoundException geworfen.
public Collection<Entry> filterEntries(Filter filter)
Liefert alle Einträge, für die der Filter gültig ist.