Java :: Aufgabe #170

1 Lösung Lösung öffentlich

Roboterfabrik Programmieraufgabe

Fortgeschrittener - Java von azy5679 - 08.05.2017 um 23:31 Uhr
In einem Zeitungsartikel lesen Sie, dass die Firma ASDF123-Roboter AG, junge und kreative Mitarbeiter
fur den Aufbau einer Roboterfabrik sucht. Von der Stellenausschreibung ganz hingerissen, machen Sie sich
sofort auf den Weg und reichen Ihre Bewerbungsunterlagen ein. Tatsachlich meldet sich die Firma kurz
darauf bei Ihnen und ladt Sie zu einem Bewerbungsgesprach ein. Fur Sie lauft scheinbar alles perfekt und
Sie konnen es kaum erwarten Ihren zukunftigen Arbeitgeber von Ihren Qualitaten zu uberzeugen. Jedoch
zeigt dieser keinerlei Interesse an Ihren Zeugnissen, sondern knupft vielmehr Ihre Einstellung an die Losung
folgender Aufgabe.
Die Firma ASDF123-Roboter AG mochte eine neue Roboterfabrik aufbauen, benotigt dazu aber ein Softwaremodell,
welches den Produktionsprozess und die Roboter simuliert. Es handelt sich nur um eine einzige
Fabrik, die
exibel auf Bestellungen der Kunden reagieren kann. Die Roboterfabrik bietet ihren Kunden
zwei verschiedene Modelle an, beide aus der Star-Wars-Produktreihe: die Modelle heien C3PO und R2D2.
Alle Roboter haben eine einfache Schnittstelle (Robot), mit der sie gesteuert werden konnen. Diese Schnittstelle
sieht wie im folgenden dargestellt aus.

Quellcode ausblenden Java-Code
    
public interface Robot extends RobotControl, RobotInstructions {
// keine eigenen Methoden
}
/**
* Das Interface reprasentiert einen einfachen Roboter mit seinen Funktionen.
*
* Jeder produzierte Roboter hat einen Namen, der vom Besteller frei gewahlt
* werden kann. Der Name bleibt uber die gesamte Lebensdauer des Roboters
* unveranderlich. Man kann einen Roboter jederzeit uber die
* <code>getName()</code>-Methode nach seinem Namen fragen.
*
* Zusatzlich zum frei gewahlten Namen, hat jeder Roboter noch eine
* Seriennummer. Diese wird bei der Produktion festgelegt und hat einen vom
* Roboter-Typ abhangigen Bereich moglicher Werte. Innerhalb des Bereiches wird
* die Seriennummer zufallig vergeben. Die Seriennummer kann auch bei
* ausgeschalteten Roboter uber <code>getId()</code>gelesen werden.
*
* Ein Roboter hat einen Hauptschalter, der mithilfe der
* <code>triggerPowerSwitch()</code>-Methode bedient werden kann. Direkt nach
* der Produktion ist der Roboter ausgeschaltet. Druckt man einmal auf den
* Schalter, wird er eingeschaltet. Ein weiterer Druck schaltet ihn wieder aus, usw.
*
* Die aktuelle Position des Hauptschalters kann man mit der Methode
* <code>isPowerOn()</code> abfragen. Hierbei bedeutet <code>true</code>, dass
* der Roboter eingeschaltet ist und <code>false</code>, dass er nicht
* eingeschaltet ist.
*
1
* Falls ein Fehler auftritt, kann der Nutzer des Roboters den letzten
* aufgetretenen Fehler uber eine Blackbox (Fehlerspeicher) auslesen. Dies
* geschieht mithilfe der <code>getLastException()</code>-Methode. Der
* Fehlerspeicher kann auch bei ausgeschaltetem Roboter benutzt werden. Gab es
* noch keinen Fehler, ist der Fehlerspeicher leer (<code>null</code>).
*
* Alle Methoden dieses Interfaces konnen auch auf einem Roboter aufgerufen
* werden, der ausgeschaltet ist (d.h. wenn <code>isPowerOn()</code> == false).
*/
public interface RobotControl {
/**
* Gibt die ID (Seriennummer) des Roboters zuruck.
*
* @return Eine eindeutige Identifikation in Form einer Zahl.
*/
public int getId();
/**
* Gibt den Namen des Roboter-Exemplars zuruck.
*
* @return Der Name des Roboters.
*/
public String getName();
/**
* Betatigen den An-/Ausschaltknopf.
*/
public void triggerPowerSwitch();
/**
* Pruft ob der Roboter eingeschaltet ist.
*
* @return <code>true</code> bedeutet, dass der Roboter eingeschaltet ist,
* <code>false</code>, dass er nicht eingeschaltet ist.
*/
public boolean isPowerOn();
/**
* Ruft die zuletzt aufgetretene Ausnahme aus der Blackbox ab.
*
* @return zuletzt aufgetretene Ausnahme oder <code>null</code> falls noch
* keine aufgetreten ist.
*/
public RobotException getLastException();
}
/**
* Das Interface reprasentiert den Befehlssatz eines einfachen Roboters.
*
* Jeder Roboter kann zwei grundlegende Operationen durchfuhren: das Umwandeln
* einer Menge von Zahlen in einen String (<code>speak(...)</code>) und das
* sortieren eines Arrays von Zahlen (<code>think(...)</code>). Wie genau das
* Sortieren oder die Umwandlung erfolgt, hangt vom jeweiligen Typ des Roboters ab.
*
* Zu beachten ist, dass die Methoden dieses Interfaces nur auf Robotern benutzt
* werden konnen, die eingeschaltet sind. Versucht man sie auf einem
* ausgeschalteten Roboter zu benutzen, werfen sie eine {@link RobotIllegalStateException}.
*
* Weiterhin haben alle Roboter einen kleinen technischen Defekt, der dazu fuhrt
* dass die Methoden dieses Interfaces absturzen, wenn in den Eingabedaten ein
* spezieller Wert vorkommt. Immer wenn (<code>speak(...)</code>) oder (
* <code>think(...)</code>) mit einem Array aufgerufen werden, das irgendwo die
* Zahl {@literal 42} enthalt, verweigern sie ihren Dienst und werfen eine
* {@link RobotMagicValueException}.
*/
2
public interface RobotInstructions {
/**
* Gibt ein Array von Zahlen als String zuruck. Die Zahlen werden
* <b>nicht</b> sortiert.
*
* @param zahlen Zahlen, die ausgegeben werden sollen.
* @return Zahlen als String
* @throws RobotException wenn der Roboter in einem ungultigen Zustand ist,
* oder das Array nicht seinen Vorstellungen entspricht.
*/
public String speak(int[] zahlen) throws RobotException;
/**
* Sortiert ein Array von Zahlen. Die Reihenfolge hangt von dem Typ des
* Roboters ab.
*
* @param zahlen Zahlen, die sortiert werden sollen.
* @return Sortierte Zahlen
* @throws RobotException wenn der Roboter in einem ungultigen Zustand ist,
* oder das Array nicht seinen Vorstellungen entspricht.
*/
public int[] think(int[] zahlen) throws RobotException;
}


Die Fabrik ist von ihren Fertigungsanlagen her so konzipiert, dass jeder Roboter einzeln gefertigt wird.
Ubergeben wird lediglich das gewunschte Roboter-Modell und der Name und schon erhalt der Kunde den
von ihm gewunschten Roboter.
Der Unterschied zwischen den angebotenen Modellen liegt in der Ausfuhrung der Befehle aus dem Interface
RobotInstructions. Wahrend R2D2 Arrays immer aufsteigend sortiert und bei der Umwandlung in ein
Array den Inhalt durch Kommas trennt (z. B. 1, 2, 3, 4, 5, 6), sortiert C3PO Arrays stets absteigend
und wandelt deren Inhalt in einen String mit Semikolon als Trennzeichen um (z. B. 6; 5; 4; 3; 2; 1).
Die Seriennummern der R2D2-Modelle bewegen sich im Bereich von 0{9999, die der C3PO-Modelle von
10000{19999.
(a) Schreiben Sie die in den Interfaces referenzierten Klassen fur die Ausnahmen. Sorgen Sie dafur, dass die
Ausnahmen den Namen des Roboters tragen in dem sie entstanden sind und dass man diesen Namen
uber die Methode getRobotName() wieder auslesen kann.
(b) Programmieren Sie zwei Klassen R2D2 und C3PO, die beide das Interface Robot implementieren. Lesen
Sie bitte sorgfaltig die Dokumentation der Interfaces, damit Sie die beschriebene Semantik in Ihrer
Implementierung einhalten.
Tipp: Denken Sie daran, keinen Code zu duplizieren und fuhren Sie gegebenenfalls weitere Klassen ein,
um dies zu vermeiden.
(c) Entwickeln Sie eine Klasse RobotFactory mit deren Hilfe man Instanzen der beiden Roboter-Typen
erzeugen kann. Eine Enumeration mit dem Namen RobotType dient dazu, bei der Erzeugung anzugeben,
ob man einen R2D2- oder einen C3PO-Roboter haben mochte.
Vergessen Sie nicht, dass jeder Roboter eine Seriennummer aus dem jeweiligen Bereich benotigt und
dass er bei der Erzeugung seinen unveranderlichen Namen bekommt.
Verbergen Sie die Implementierung der Roboter vor dem Verwender und erlauben Sie nur Zugri auf
die Factory, die Interfaces und die Ausnahmen. Wahlen Sie entsprechende Pakete gema ihrem Schema,
um dies zu realisieren.
(d) Zusatzlich zu den beiden produzierten Roboter-Modellen R2D2 und C3PO steht in der Firma noch
ein alter Nexus-6-Roboter mit dem Namen Pris herum, der leider seit einer Begegnung mit einem
Blade-Runner irreparabel defekt ist und nicht eingeschaltet werden kann (man kann den Schalter zwar
drucken, dies hat aber keine Wirkung). Da es nur dieses eine Exemplar gibt, konnen auch keine weiteren
Nexus-6-Modelle hergestellt werden.

Implementieren Sie den Nexus-6-Roboter (Klassenname Nexus6) als Singleton. Beachten Sie, dass die
speak- und think-Methoden nicht funktionieren, sondern grundsatzlich eine Ausnahme (RobotIllegal-
StateException) werfen.
(e) Schreiben Sie automatisierte JUnit-Tests mit denen Sie die korrekte Funktionsweise der Implementierungen
und der Factory-Klasse uberprufen. Legen Sie die Tests in ein anderes Paket als die Implementierung.
Denken Sie daran, auch die Ausnahmen zu testen.
(f) Angenommen, Ihre Firma mochte eine weitere Produktlinie ero nen und in Zukunft auch noch T1000-
Roboter herstellen { die naturlich auch das Roboter-Interface implementieren. Welche Anderungen
mussten Sie an Ihrem Projekt durchfuhren?
Sie brauchen keine Implementierung durchzufuhren. Sie sollen aber kurz erlautern, an welchen Stellen
Sie Ihr Projekt erweitern mussten. Gehen Sie dabei auch auf die Frage ein, welche Auswirkungen dies
auf die bereits produzierten Roboter und deren Verwender hatte.

Lösungen:

vote_ok
von meisen (330 Punkte) - 01.09.2017 um 08:22 Uhr
Quellcode ausblenden Java-Code
public abstract class Robot implements RobotControl, RobotInstructions{

    private boolean powerState;
    
    private RobotException lastException;
    private String name;
    private int Id;


    Robot(int IdRange, String name){
        this.Id = (int) (Math.random() * 10000) + IdRange;
        this.name = name;
        powerState=false;
    }

    public void setLastException(RobotException lastException) {
        this.lastException = lastException;
    }

    @Override
    public int getId() {
        return this.Id;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public void triggerPowerSwitch() {
        powerState = !powerState;
    }

    @Override
    public boolean isPowerOn() {
        return powerState;
    }

    @Override
    public RobotException getLastException() {
        return lastException;
    }

    String speak(int[] zahlen, char trennZeichen) throws RobotException {
        if(!powerState) throw new RobotIllegalStateException(this);
        return generateString(zahlen, trennZeichen);
    }

    boolean contains42(int[] zahlen){
        return generateString(zahlen, '-').contains("4-2");
    }

    private String generateString(int[] zahlen, char trennZeichen){
        String s = "";
        for (int zahl:zahlen)
            s += "" + zahl + trennZeichen;
        return s;
    }
}


Quellcode ausblenden Java-Code
public class R2D2 extends Robot{

    final static char TRENNZEICHEN = ',';

    R2D2(String name){
        super(0, name);
    }

    @Override
    public String speak(int[] zahlen) {
        return super.speak(think(zahlen), TRENNZEICHEN);
    }

    @Override
    public int[] think(int[] zahlen){
        //System.out.println(contains42(zahlen));
        if (contains42(zahlen)) throw new RobotMagicValueException(this);
        Arrays.sort(zahlen);
        return zahlen;
    }
}


Quellcode ausblenden Java-Code
public class C3PO extends Robot{

    final static char TRENNZEICHEN = ';';


    C3PO(String name){
        super(10000, name);
    }

    @Override
    public String speak(int[] zahlen) {
        return super.speak(think(zahlen), TRENNZEICHEN);
    }

    @Override
    public int[] think(int[] zahlen){
        if (contains42(zahlen)) throw new RobotMagicValueException(this);
        List<Integer> zahlList = new ArrayList<>();
        for (int zahl:zahlen)
            zahlList.add(zahl);
        Collections.sort(zahlList, Collections.reverseOrder());
        for (int i = 0; i < zahlen.length; i++)
            zahlen[i] = zahlList.get(i);
        return zahlen;
    }
}


Quellcode ausblenden Java-Code
public class RobotException extends RuntimeException{

    String robotName;
    public RobotException(){
        System.err.println("RobotException");
    }

    RobotException(Robot robot){
        super( "Robotname " + robot.getName() );
        robot.setLastException(this);
    }
}


Quellcode ausblenden Java-Code
class RobotIllegalStateException extends RobotException {

    RobotIllegalStateException(Robot robot) {
        super(robot);
    }
}


Quellcode ausblenden Java-Code
class RobotMagicValueException extends RobotException {

    RobotMagicValueException(Robot robot){
        super( robot );
    }
}