Zum Menü springen Zum Inhalt springen

iamBlog

Java: Timer & Callbacks

07.05 2008 08:27

In der aktuellen Aufgabe dürfen wir ein bisschen Gott spielen und am Rad der Zeit drehen. Unsere mittlerweile schon ziemlich umfangreiche Videothek wird nun wieder einmal erweitert. Diesmal um die Mitarbeiter, die ihren Lohn pünktlich auf ihrem Konto haben wollen!

Da die Welt ja schon geschaffen ist, lasst uns ein Stück Binären Lehm in die Hände nehmen und daraus ein paar Mitarbeiter formen, die auch noch unterschiedlich viel Lohn erhalten können. (Aufgabe A) Anschließend müssen wir uns noch die Sanduhr von Väterchen Zeit "ausleihen" und diese für unser Vorhaben präparieren. In der Digitalen Welt geht dies ja einfach und schon bald können sich unsere Mitarbeiter auf einen Geldregen freuen. (Aufgabe B) Unsere letzte Aufgabe besteht darin, dem Ganzen Leben einzuhauchen und unser hoffentlich funktionierendes Werk zu bewundern.

Nach einer mal anderen Einleitung geht es nun frisch ans Werk ;)

Aufgabe A: Personal erschaffen

Der Mitarbeiter

Wie soll er aussehen?

Ein Blick auf das gegebene UML-Diagramm verrät uns schon, dass er einen Namen, Vornamen, eine Adresse, eine Mitarbeiternummer und ein Anstellungsverhältnis braucht. Wenn man diese Informationen in eine Klasse steckt ist unser Mitarbeiter auch schon fertig! (fürs Erste ;) )


public class Mitarbeiter{
    private String Name;
    private String Vorname;
    private String Mitarbeiternummer;
    private Adresse Anschrift;
    private Anstellungsverhaeltnis anstellungsverhaeltnis;
    
    public Mitarbeiter(String Name, String Vorname, Adresse Anschrift){
        this.Name = Name;
        this.Vorname = Vorname;
        this.Anschrift = Anschrift;
    }
    
    public void setMitarbeiternummer(String Mitarbeiternummer){
        this.Mitarbeiternummer = Mitarbeiternummer;
    }
    
    public void setAnstellungsverhaeltnis(Anstellungsverhaeltnis anstellungsverhaeltnis) {
        this.anstellungsverhaeltnis = anstellungsverhaeltnis;
    }
    
// <- Hier fehlen noch ein paar Getter-Methoden

    public String toString(){
        return Name + " " + Vorname + " | " + Mitarbeiternummer;
    }
}

Und jetzt?

Jetzt müssen wir das Anstellungsverhältnis unseres Mitarbeiter modellieren!

Die Klasse Anstellungsverhältnis:


abstract class Anstellungsverhaeltnis {
    private String Name;
    
    public Anstellungsverhaeltnis(String Name){
        this.Name = Name;
    }

    public String getName() {
        return Name;
    }
}

Diese Klasse ist Abstrakt - d. h. es kann nie eine Instanz von ihr generiert werden. Muss - und soll man ja auch nicht, da unsere Anstellungsverhältnisse Kinder dieser Klasse und damit wieder instanzierbar sind.

Erstgeborenes:


public class Festangestellt 
extends Anstellungsverhaeltnis{

    private float Gehalt;
    private final int ZAHLTAG = 1;
    
    public Festangestellt(String Name, float Gehalt) {
        super(Name);
        this.Gehalt = Gehalt;
    }

    public void getPayed(Calendar currentTime){
        if(currentTime.get(Calendar.DAY_OF_MONTH) == ZAHLTAG){
            DateFormat date = DateFormat.getDateInstance(DateFormat.SHORT);
            NumberFormat currency = NumberFormat.getCurrencyInstance();
            System.out.println("<< " + date.format(currentTime.getTime()) + " - Gehaltszahlung an " + super.getName() + ": " + currency.format(Gehalt) + " (Festangestellt)");
        }
    }
}

Das Zweite:


public class Lehrling
extends Anstellungsverhaeltnis{

    private float Gehalt;
    private final int ZAHLTAG = 15;
    
    public Lehrling(String Name, float Gehalt) {
        super(Name);
        this.Gehalt = Gehalt;
    }
    
    public void getPayed(Calendar currentTime){
        if(currentTime.get(Calendar.DAY_OF_MONTH) == ZAHLTAG){
            DateFormat date = DateFormat.getDateInstance(DateFormat.SHORT);
            NumberFormat currency = NumberFormat.getCurrencyInstance();
            System.out.println("<< " + date.format(currentTime.getTime()) + " - Gehaltszahlung an " + super.getName() + ": " + currency.format(Gehalt) + " (Lehrling)");
        }
    }
}

Der Nachzügler:


public class Teilzeit 
extends Anstellungsverhaeltnis{

    private float hPerMonth;
    private float gPerHour;
    private final int ZAHLTAG = 15;
    
    public Teilzeit(String Name, float hPerMonth, float gPerHour) {
        super(Name);
        this.hPerMonth = hPerMonth;
        this.gPerHour = gPerHour;
    }
    
    public void getPayed(Calendar currentTime){
        if(currentTime.get(Calendar.DAY_OF_MONTH) == ZAHLTAG){
            DateFormat date = DateFormat.getDateInstance(DateFormat.SHORT);
            NumberFormat currency = NumberFormat.getCurrencyInstance();
            System.out.println("<< " + date.format(currentTime.getTime()) + " - Gehaltszahlung an " + super.getName() + ": " + currency.format(hPerMonth * gPerHour) + " (Teilzeit)");
        }
    }
}

Viel kann man zu diesen Dreien nicht sagen... Wenn Zahltag ist... gibts cash ;)

Die Mitarbeiternummer:

Die Mitarbeiternummerzuweisung habe ich wieder in die Klasse Videothek gesteckt, da es einfach logischer ist. (ein Mitarbeiter kriegt die Nummer ja von der Videothek zugewiesen und denkt sich diese nicht selber aus)


public String generateWorkerNumber(String Name, String Vorname){
        String ret = "";
        if(Name.length() > 2){
            ret += Name.substring(0, 2);
        } else {
            String x = Name;
            for(int a = Name.length(); a < 2 ; a++){
                x = x + '_';
            }
            ret += x;
        }
        
        if(Vorname.length() > 2){
            ret += Vorname.substring(0, 2);
        } else {
            String x = Vorname;
            for(int a = Vorname.length(); a < 2 ; a++){
                x = x + '_';
            }
            ret += x;
        }
        
        ret += fitTable(Integer.toString(arbeiterListe.getLength()) , 4, '0');
        
        return ret;
    }

Die Mitarbeiter werden in der Videothek wieder von "Set" verwaltet.

Aufgabe B: Die Sache mit dem lieben Geld

Hui. Was muss ich da tun?

Hier hilft wiederum ein Blick auf das UML-Diagramm: Ein Interface VideoTimeCallback und eine Klasse Zeitgeber schreiben.

Das Interface:


public interface VideoTimeCallback {
    void onTimeEventOccured(Calendar currentTime);
}

Wenn man dieses dann wie gefordert in Mitarbeiter einbindet, wird man schnell darauf hingewiesen, dass die Methode onTimeEventOccured noch nicht vorhanden ist. Doch was soll beim Aufruf dieser Methode passieren?

Es soll die Methode gehaltBezahlen, die ebenfalls in der Klasse Mitarbeiter verbaut ist aufgerufen werden.


    public void onTimeEventOccured(Calendar currentTime) {
        gehaltBezahlen(currentTime);
    }

    public void gehaltBezahlen(Calendar currentTime){
        if(anstellungsverhaeltnis instanceof Festangestellt){
            Festangestellt tmp = (Festangestellt) anstellungsverhaeltnis;
            tmp.getPayed(currentTime);
        }
        if(anstellungsverhaeltnis instanceof Lehrling){
            Lehrling tmp = (Lehrling) anstellungsverhaeltnis;
            tmp.getPayed(currentTime);
        }
        if(anstellungsverhaeltnis instanceof Teilzeit){
            Teilzeit tmp = (Teilzeit) anstellungsverhaeltnis;
            tmp.getPayed(currentTime);
        }
    }

Bei jedem Aufruf der Methode wird überprüft, welches Anstellungsverhältnis der Mitarbeiter hat. Anschließend wird die individuelle getPayed-Methode aufgerufen, die überprüft, ob dieser Mitarbeiter am heutigen Tage (currentTime) sein Gehalt bekommt.

Einfacher geht es allerdings, wenn wir eine abstrakte Methode gehaltBezahlen in unsere Klasse Anstellungsverhaeltnis stecken:


abstract void getPayed(Calendar currentTime);

Dann können wir in der Zeitgeber-Klasse die Methode erheblich verkürzen und somit verbessern:


    public void gehaltBezahlen(Calendar currentTime){
        anstellungsverhaeltnis.getPayed(currentTime);
    }

Nun kommt die künstliche Zeit ins Spiel:

Berücksichtigen Sie, dass in Ihrem Programmpaket nur eine Instanz der Klasse Zeitgeber exisitieren darf.<<

=> Singleton!


public class Zeitgeber extends TimerTask{
    private static Zeitgeber instance = null;
    private int Zeitfortschritt = 0;
    
    private Calendar currentTime = Calendar.getInstance();
    private Set registeredStaff = new Set(2);

    private Zeitgeber(){
    }
    
    public static Zeitgeber getInstance(){
        if(instance == null){
            instance = new Zeitgeber();
        }
        return instance;
    }

    public void setZeitfortschritt(int zeitfortschritt) {
        Zeitfortschritt = zeitfortschritt;
    }
    
    public void run() {
        currentTime.add(Calendar.DAY_OF_MONTH, zeitfortschritt);
        
        VideoTimeCallback tmp = null;
        for(int i = 0; i < registeredStaff.getLength(); i++){
            tmp = (VideoTimeCallback) registeredStaff.get(i);
            tmp.onTimeEventOccured(currentTime);
        }
    }
    
    public void registerCallback(VideoTimeCallback callback){
        registeredStaff.add(callback);
    }
}

Hier geschehen nun die Dinge, auf die sich unsere Mitarbeiter jeden Monat freuen ;)

In der Methode registerCallback werden die Mitarbeiter für die Gehaltsüberweisung registriert - in diesem Fall in ein "Set" eingetragen. Bei jedem Aufruf der run-Methode wird ein Tag vergangen (er vergeht ja nicht selbständig so schnell ;) ) - und mit dem vergangenen Tag stellt sich auch die Frage, ob es wieder Zahltag ist... In der for-Schleife werden alle registrierten Mitarbeiter abgearbeitet und überprüft ob diese Geld bekommen.

Aufgabe C: Die Stunde der Wahrheit


public class Testsuite {
    public static void main(String[] args){
        
        Videothek video = new Videothek();

        Zeitgeber fatherTime = Zeitgeber.getInstance();
        fatherTime.setZeitfortschritt(1);
        
        Timer timer  = new Timer();
        timer.scheduleAtFixedRate( fatherTime , 1000, 100);
        
        /***************************************
         *   Mitarbeitererstellung
         ***************************************/
        
        Mitarbeiter Mitarbeiter1 = new Mitarbeiter("Huber", "Peter", null);
        Mitarbeiter1.setAnstellungsverhaeltnis(new Festangestellt(Mitarbeiter1.getName(), 8000.00f));
        video.addMitarbeiter(Mitarbeiter1);
        fatherTime.registerCallback(Mitarbeiter1);
        
        Mitarbeiter Mitarbeiter2 = new Mitarbeiter("Hinterhuber", "Franz", null);
        Mitarbeiter2.setAnstellungsverhaeltnis(new Lehrling(Mitarbeiter2.getName(), 700.00f));
        video.addMitarbeiter(Mitarbeiter2);
        fatherTime.registerCallback(Mitarbeiter2);
        
        Mitarbeiter Mitarbeiter3 = new Mitarbeiter("Müller", "Petra", null);
        Mitarbeiter3.setAnstellungsverhaeltnis(new Teilzeit(Mitarbeiter3.getName(), 12.50f, 24.00f));
        video.addMitarbeiter(Mitarbeiter3);
        fatherTime.registerCallback(Mitarbeiter3);
        
        video.listMitarbeiter();
        
    }
}

An der Stelle, bei der im Code null steht, kann man natürlich auch eine Adresse einfügen. Einfach zuvor ein Adressen-Objekt erstellen und null dann mit diesem ersetzen.

Viel Spaß beim coden ;)

Kommentare

  1. 1

    Hallo Mr. Felber, mal wieder eine (fast) perfekte Lösung. Wie immer hab ich noch ein paar ergänzende Vorschläge für den Java Gott ;) (haha - Wortspiel)

    Es steht noch in der Angabe, dass der Zeitfortschritt variabel gehalten werden soll. currentTime.add(Calendar.DAYOFMONTH, 1); ist recht statisch bei ihnen. Ne schnuckelige Variable mit Setter sollte da genügen.

    Und zum Thema abstracte Methoden: Versuchen sie doch mal die public void getPayed(Calendar currentTime) im Arbeitsverhaeltnis abstract zu definieren, dann sparen sie sich ihren (redundanten) instanceof Block. Die bezahlen Methode wird dann schön kurz.

    Ansonsten Sonderlob für das Singleton und weil ich mir denken kann dass mancheiner die Aufgabenstellung 3x lesen muss, um sie auch wirklich zu verstehen... (so wie ich - was ist bitte ein Quarz/Trigger?)

    Kommentar von Gregor Liebermann am 07. 05. 2008 um 17:12 Uhr
  2. 2

    Danke für die Hinweise. Habs gleich mal aktualisiert. :)

    Kommentar von Dominik Felber am 08. 05. 2008 um 10:28 Uhr
  3. 3

    Singleton macht auf alle Fälle Sinn... aber man sollte dazu noch den Konstruktor private deklarieren da man sonst ja doch wieder Objekte vom Zeitgeber erzeugen kann.

    Kommentar von Thomas Höfer am 15. 05. 2008 um 22:27 Uhr
  4. Dieser Eintrag kann nicht mehr kommentiert werden.

Nächster Eintrag: iam Boot Screen für WinXP

Vorheriger Eintrag: Java: Interfaces

Über den iamBlog

Der iamBlog ist von und für Studenten der FH Augsburg und alle Leute die sich für Design, Medien und Multimedia interessieren.

Namensgebend war der Studiengang InterAktive Medien an der FH Augsburg.

Der Blog befindet sich Moment noch im Aufbau. Wir entschuldigen uns für eventuell fehlende Funktionen und den ein oder anderen Fehler im System.

Die neuesten Links

Kategorien

Das neueste Design

Avant von pichfl

Zum Auswählen eines Designs einfach oben links auf den Button Hintergrund ändern klicken.

Feeds

Die Einträge im Blog lassen sich als Atom-Feed abonnieren. Außerdem gibt es einen kombinierten Atom-Feed, der Blogeinträge und Links enthält.
Diese Feeds werden z.B. von Browsern wie Safari oder Mozilla Firefox, Newsreadern wie NetNewsWire oder Feadreader oder Onlinediensten wie Google Reader unterstützt und werden automatisch aktualisiert, wenn neue Einträge im iamBlog vorhanden sind.

Werbung

Disclaimer

This page will never work with Internet Explorer. If you use Internet Explorer to view this page, all styles and features are deactivated. Use Firefox, Safari or Opera to see all the beautiful colours of the internet.