Epic Cosmos 1: die Objekte im All
Kurz gesagt: Ein Spiel mit Objekten: Sterne, Planeten und Satelliten sind Klassen, die Regel „wer wen umkreist“ ist eine gemeinsame Methode, und eine ungültige Umlaufbahn wirft eine eigene Exception.
Problem
Das Wettrennen im All
Die Menschheit kann jetzt zu fernen Planeten fliegen. Konzerne und Staaten wetteifern um ihre Ressourcen. Du leitest eine der Missionen und willst die stärkste Macht im All werden.
Die Regeln von Epic Cosmos:
- Punkte bekommst du für das Entdecken neuer Planeten und Objekte, den Abbau von Ressourcen, den Bau von Gebäuden und Schiffen und wissenschaftliche Entdeckungen.
- Die Objekte sind Sterne, Planeten und Satelliten. Ein Stern liefert Energie. Manche Planeten haben seltene Ressourcen, und ihre Atmosphäre entscheidet, was man dort bauen kann. Ein Satellit dient der Kommunikation und der Aufklärung.
- Ressourcen brauchst du zum Bauen, für die Forschung und um deine Basen und Schiffe zu unterhalten.
- Gebäude bauen Ressourcen ab, erforschen Technologien, schützen die Basis und bauen Schiffe.
- Technologien schalten neue Gebäude, Schiffe und Fähigkeiten frei.
- Konflikte: Im All bist du nicht allein. Es gibt Piraten und andere Spieler.
- Das Ende: Das Spiel ist vorbei, wenn jemand eine bestimmte Punktzahl erreicht oder nach einer bestimmten Anzahl von Zügen. Es gewinnt, wer die meisten Punkte hat.
Vor den Gebäuden und Schiffen brauchst du die Welt selbst: welche Objekte es gibt, wo sie sind und was wen umkreisen kann. Das ist diese Lektion. Ressourcen, Gebäude und Schiffe kommen in der nächsten.
Die Idee
Alles im All ist ein SpaceObject
Ein Stern, ein Planet und ein Satellit haben etwas gemeinsam: einen Namen, Koordinaten x, y, z und eine Masse. Das Gemeinsame kommt in eine abstrakte Klasse:
abstract class SpaceObject { private String name; private double coordinateX; private double coordinateY; private double coordinateZ; private double mass;
public SpaceObject(String name, double coordinateX, double coordinateY, double coordinateZ, double mass) { this.name = name; this.coordinateX = coordinateX; this.coordinateY = coordinateY; this.coordinateZ = coordinateZ; this.mass = mass; }
public String getName() { return name; }
public double getCoordinateX() { return coordinateX; }
public double getCoordinateY() { return coordinateY; }
public double getCoordinateZ() { return coordinateZ; }
public double getMass() { return mass; }
public abstract String getKind();
public void displayInfo() { System.out.printf("%s %s: (%.1f, %.1f, %.1f), Masse %.2f%n", getKind(), name, coordinateX, coordinateY, coordinateZ, mass); }
protected void moveTo(double x, double y, double z) { coordinateX = x; coordinateY = y; coordinateZ = z; }}abstract class SpaceObject{ public string Name { get; } public double CoordinateX { get; private set; } public double CoordinateY { get; private set; } public double CoordinateZ { get; private set; } public double Mass { get; }
public SpaceObject(string name, double coordinateX, double coordinateY, double coordinateZ, double mass) { Name = name; CoordinateX = coordinateX; CoordinateY = coordinateY; CoordinateZ = coordinateZ; Mass = mass; }
public abstract string GetKind();
public void DisplayInfo() { Console.WriteLine($"{GetKind()} {Name}: ({CoordinateX:F1}, {CoordinateY:F1}, {CoordinateZ:F1}), Masse {Mass:F2}"); }
protected void MoveTo(double x, double y, double z) { CoordinateX = x; CoordinateY = y; CoordinateZ = z; }}class SpaceObject(ABC): def __init__(self, name, coordinate_x, coordinate_y, coordinate_z, mass): self._name = name self._coordinate_x = coordinate_x self._coordinate_y = coordinate_y self._coordinate_z = coordinate_z self._mass = mass
@property def name(self): return self._name
@property def coordinate_x(self): return self._coordinate_x
@property def coordinate_y(self): return self._coordinate_y
@property def coordinate_z(self): return self._coordinate_z
@property def mass(self): return self._mass
@abstractmethod def get_kind(self): pass
def display_info(self): print(f"{self.get_kind()} {self._name}: ({self._coordinate_x:.1f}, {self._coordinate_y:.1f}, {self._coordinate_z:.1f}), Masse {self._mass:.2f}")
def _move_to(self, x, y, z): self._coordinate_x = x self._coordinate_y = y self._coordinate_z = zclass SpaceObject { #name; #coordinateX; #coordinateY; #coordinateZ; #mass;
constructor(name, coordinateX, coordinateY, coordinateZ, mass) { this.#name = name; this.#coordinateX = coordinateX; this.#coordinateY = coordinateY; this.#coordinateZ = coordinateZ; this.#mass = mass; }
get name() { return this.#name; }
get coordinateX() { return this.#coordinateX; }
get coordinateY() { return this.#coordinateY; }
get coordinateZ() { return this.#coordinateZ; }
get mass() { return this.#mass; }
getKind() { throw new Error(`${this.constructor.name} muss getKind() schreiben`); }
displayInfo() { console.log(`${this.getKind()} ${this.#name}: (${this.#coordinateX.toFixed(1)}, ${this.#coordinateY.toFixed(1)}, ${this.#coordinateZ.toFixed(1)}), Masse ${this.#mass.toFixed(2)}`); }
_moveTo(x, y, z) { this.#coordinateX = x; this.#coordinateY = y; this.#coordinateZ = z; }}- Die Koordinaten sind in Millionen Kilometern von der Sonne, und die Masse ist in Erdmassen: Die Erde ist 1, die Sonne 333.000.
displayInfo()ist allen gemeinsam. Die Art (getKind()) ist abstrakt: Jede Unterklasse sagt selbst, was sie ist.-
#nameund die anderen Felder mit#sind wirklich versteckt: Von außen kommst du nicht heran, du liest sie überget name(). Nur ist#auch in Unterklassen nicht sichtbar, und einprotectedgibt es in JavaScript nicht. Darum hat_moveToeinen Unterstrich: eine Absprache für „nur für Unterklassen“, die JavaScript nicht durchsetzt.
JavaScript hat keine abstrakten Klassen und Methoden. Am nächsten kommt, dass getKind() in der Basisklasse einen Fehler wirft: Eine Unterklasse, die sie nicht schreibt, merkt es beim ersten Aufruf. Ein Objekt so einer Klasse wird ohne Probleme erzeugt:
class Comet extends SpaceObject {}
const comet = new Comet("Halley", 0, 0, 0, 0);try { comet.displayInfo();} catch (e) { console.log(e.message);}Comet muss getKind() schreibenDer Stern ist die einfachste Unterklasse:
class Star extends OrbitableSpaceObject { public Star(String name, double coordinateX, double coordinateY, double coordinateZ, double mass) { super(name, coordinateX, coordinateY, coordinateZ, mass); }
@Override public String getKind() { return "Stern"; }}class Star : OrbitableSpaceObject{ public Star(string name, double coordinateX, double coordinateY, double coordinateZ, double mass) : base(name, coordinateX, coordinateY, coordinateZ, mass) { }
public override string GetKind() { return "Stern"; }}class Star(OrbitableSpaceObject): def get_kind(self): return "Stern"class Star extends OrbitableSpaceObject { getKind() { return "Stern"; }}Der Konstruktor wird geerbt: new Star(...) ruft den der Basisklasse mit denselben Argumenten auf. Darum schreibt Star nur seine Art.
Die drei Arten von Objekten liegen in einem Array von SpaceObject. Die Schleife weiß nicht, was was ist, und jedes Objekt sagt seine eigene Art:
SpaceObject[] objects = { new Star("Sonne", 0, 0, 0, 333000), new Planet("Erde", 149.6, 0, 0, 1), new Satellite("Mond", 150, 0, 0, 0.012),};for (SpaceObject object : objects) { object.displayInfo();}Stern Sonne: (0.0, 0.0, 0.0), Masse 333000.00Planet Erde: (149.6, 0.0, 0.0), Masse 1.00Satellit Mond: (150.0, 0.0, 0.0), Masse 0.01SpaceObject[] objects ={ new Star("Sonne", 0, 0, 0, 333000), new Planet("Erde", 149.6, 0, 0, 1), new Satellite("Mond", 150, 0, 0, 0.012),};foreach (SpaceObject spaceObject in objects){ spaceObject.DisplayInfo();}Stern Sonne: (0.0, 0.0, 0.0), Masse 333000.00Planet Erde: (149.6, 0.0, 0.0), Masse 1.00Satellit Mond: (150.0, 0.0, 0.0), Masse 0.01objects = [ Star("Sonne", 0, 0, 0, 333000), Planet("Erde", 149.6, 0, 0, 1), Satellite("Mond", 150, 0, 0, 0.012),]for space_object in objects: space_object.display_info()Stern Sonne: (0.0, 0.0, 0.0), Masse 333000.00Planet Erde: (149.6, 0.0, 0.0), Masse 1.00Satellit Mond: (150.0, 0.0, 0.0), Masse 0.01const objects = [ new Star("Sonne", 0, 0, 0, 333000), new Planet("Erde", 149.6, 0, 0, 1), new Satellite("Mond", 150, 0, 0, 0.012),];for (const spaceObject of objects) { spaceObject.displayInfo();}Stern Sonne: (0.0, 0.0, 0.0), Masse 333000.00Planet Erde: (149.6, 0.0, 0.0), Masse 1.00Satellit Mond: (150.0, 0.0, 0.0), Masse 0.01Die Idee
Objekte, die umkreist werden
Planeten umkreisen einen Stern, und Satelliten umkreisen einen Planeten. Sowohl der Stern als auch der Planet müssen sich merken, was sie umkreist. Das ist OrbitableSpaceObject: eine abstrakte Klasse zwischen SpaceObject und ihnen.
abstract class OrbitableSpaceObject extends SpaceObject { private SpaceObject[] orbiters = new SpaceObject[10]; private int orbiterCount = 0;
public OrbitableSpaceObject(String name, double coordinateX, double coordinateY, double coordinateZ, double mass) { super(name, coordinateX, coordinateY, coordinateZ, mass); }
public void addOrbiter(SpaceObject orbiter) { if (orbiterCount == orbiters.length) { throw new IllegalStateException("Um " + getName() + " kreisen schon " + orbiters.length + " Objekte"); } orbiters[orbiterCount] = orbiter; orbiterCount++; }
public SpaceObject[] getOrbiters() { SpaceObject[] result = new SpaceObject[orbiterCount]; for (int i = 0; i < orbiterCount; i++) { result[i] = orbiters[i]; } return result; }}abstract class OrbitableSpaceObject : SpaceObject{ private SpaceObject[] orbiters = new SpaceObject[10]; private int orbiterCount = 0;
public OrbitableSpaceObject(string name, double coordinateX, double coordinateY, double coordinateZ, double mass) : base(name, coordinateX, coordinateY, coordinateZ, mass) { }
public void AddOrbiter(SpaceObject orbiter) { if (orbiterCount == orbiters.Length) { throw new InvalidOperationException("Um " + Name + " kreisen schon " + orbiters.Length + " Objekte"); } orbiters[orbiterCount] = orbiter; orbiterCount++; }
public SpaceObject[] GetOrbiters() { SpaceObject[] result = new SpaceObject[orbiterCount]; for (int i = 0; i < orbiterCount; i++) { result[i] = orbiters[i]; } return result; }}class OrbitableSpaceObject(SpaceObject): CAPACITY = 10
def __init__(self, name, coordinate_x, coordinate_y, coordinate_z, mass): super().__init__(name, coordinate_x, coordinate_y, coordinate_z, mass) self._orbiters = []
def add_orbiter(self, orbiter): if len(self._orbiters) == self.CAPACITY: raise RuntimeError(f"Um {self.name} kreisen schon {self.CAPACITY} Objekte") self._orbiters.append(orbiter)
def get_orbiters(self): return list(self._orbiters)class OrbitableSpaceObject extends SpaceObject { static CAPACITY = 10; #orbiters = [];
addOrbiter(orbiter) { if (this.#orbiters.length === OrbitableSpaceObject.CAPACITY) { throw new Error(`Um ${this.name} kreisen schon ${OrbitableSpaceObject.CAPACITY} Objekte`); } this.#orbiters.push(orbiter); }
getOrbiters() { return [...this.#orbiters]; }}- Die Umkreisenden liegen in einem Array, die von allein wächst. Einen Zähler brauchst du nicht:
this.#orbiters.lengthsagt, wie viele es sind. - Um einen Stern ist Platz für 10 Objekte:
CAPACITYgehört zur Klasse und ist allen ihren Objekten gemeinsam. Wenn der Platz voll ist, wirftaddOrbitereinen einfachenError: Eine eigene Exception für den unpassenden Moment gibt es in JavaScript nicht. getOrbiters()gibt eine Kopie des Arrays zurück.
Genauer, für Neugierige
getOrbiters()gibt eine Kopie zurück, nicht das Array selbst. Sonst könnte Code von außen mitpushhinzufügen und die Prüfung auf Platz umgehen.Starerbt vonOrbitableSpaceObject, nicht direkt vonSpaceObject. So bekommt der Stern sowohl die Umkreisenden als auch alles vonSpaceObject.
Die Kopie siehst du in der Ausgabe: Was du ihr hinzufügst, erreicht den Stern nicht.
const sun = new Star("Sonne", 0, 0, 0, 333000);new Planet("Erde", 149.6, 0, 0, 1).orbit(sun);const copy = sun.getOrbiters();copy.push(new Planet("Mars", 227.9, 0, 0, 0.11));console.log(copy.length, sun.getOrbiters().length);Erde umkreist Sonne2 1Die Idee
Die Regel für die Umlaufbahnen
Ein Planet umkreist einen Stern. Ein Satellit umkreist einen Planeten. Alles andere ist ungültig. Die Objekte, die umkreisen können, haben einen gemeinsamen Vertrag:
interface Orbiter { void orbit(SpaceObject target) throws NotValidSpaceObjectException;}interface Orbiter{ void Orbit(SpaceObject target);}class Orbiter(ABC): @abstractmethod def orbit(self, target): pass// Der Vertrag Orbiter: Das Objekt hat eine Methode orbit(target), mit der es um// target kreist oder NotValidSpaceObjectError wirft.// JavaScript hat kein interface: Planet und Satellite haben einfach so eine Methode.JavaScript hat keine Interfaces. Der Vertrag ist eine Absprache: Jedes Objekt, das umkreisen kann, hat eine Methode orbit(target). Der Code, der sie benutzt, ruft sie einfach auf, ohne zu fragen, was das Objekt ist. Das nennt man Duck Typing: „Wenn es wie eine Ente läuft und wie eine Ente quakt, ist es eine Ente.“
Wenn die Regel verletzt wird, wirft orbit eine eigene Exception. Der Name sagt genau, was passiert ist:
class NotValidSpaceObjectException extends Exception { public NotValidSpaceObjectException(String message) { super(message); }}class NotValidSpaceObjectException : Exception{ public NotValidSpaceObjectException(string message) : base(message) { }}class NotValidSpaceObjectError(Exception): passclass NotValidSpaceObjectError extends Error { constructor(message) { super(message); this.name = "NotValidSpaceObjectError"; }}So setzt der Planet sie durch:
@Overridepublic void orbit(SpaceObject target) throws NotValidSpaceObjectException { if (target instanceof Star star) { star.addOrbiter(this); System.out.println(getName() + " umkreist " + star.getName()); } else { throw new NotValidSpaceObjectException(getName() + " kann " + target.getName() + " nicht umkreisen: ein Planet umkreist nur einen Stern"); }}public void Orbit(SpaceObject target){ if (target is Star star) { star.AddOrbiter(this); Console.WriteLine(Name + " umkreist " + star.Name); } else { throw new NotValidSpaceObjectException(Name + " kann " + target.Name + " nicht umkreisen: ein Planet umkreist nur einen Stern"); }}def orbit(self, target): if isinstance(target, Star): target.add_orbiter(self) print(f"{self.name} umkreist {target.name}") else: raise NotValidSpaceObjectError(f"{self.name} kann {target.name} nicht umkreisen: ein Planet umkreist nur einen Stern")orbit(target) { if (target instanceof Star) { target.addOrbiter(this); console.log(`${this.name} umkreist ${target.name}`); } else { throw new NotValidSpaceObjectError(`${this.name} kann ${target.name} nicht umkreisen: ein Planet umkreist nur einen Stern`); }}target instanceof Starprüft den Typ. Nach der Prüfung benutzt dutargetals Stern: Eine neue Variable brauchst du nicht.- Wenn die Prüfung fehlschlägt, stoppt die Exception die Methode. Der Planet wird nirgends hinzugefügt.
Satellitehat dasselbeorbit, nur dass es aufPlanetprüft.
Genauer, für Neugierige
In JavaScript verfolgt niemand, wer was wirft. Weder der Vertrag noch orbit sagen, dass es werfen kann, und nichts zwingt den Aufrufer, es abzufangen. Das Programm bricht ab, wenn niemand es abfängt, deshalb fangen wir es im Spiel immer ab. Der Name der Exception endet auf Error, wie bei den eingebauten (TypeError).
Sieh es dir an
Wer wen umkreist
const sun = new Star("Sonne", 0, 0, 0, 333000);const earth = new Planet("Erde", 149.6, 0, 0, 1);const moon = new Satellite("Mond", 150, 0, 0, 0.012);tryOrbit(earth, sun);tryOrbit(moon, earth);tryOrbit(moon, sun);Schritt für Schritt, in Worten
- Drei Objekte: ein Stern, ein Planet und ein Satellit, jedes mit eigenen Koordinaten und eigener Masse.
- Ein Planet um einen Stern: Die Regel erlaubt es, und die Erde startet auf ihre Umlaufbahn.
- Ein Satellit um einen Planeten: erlaubt. Der Mond umkreist die Erde und bewegt sich mit ihr.
- Ein Satellit um einen Stern: orbit wirft NotValidSpaceObjectError, und das catch in tryOrbit gibt aus, warum.
Die Erde besteht die Prüfung des Sterns und wird zu den Objekten hinzugefügt, die ihn umkreisen. Der Mond besteht die Prüfung der Erde. Wenn der Mond versucht, die Sonne zu umkreisen, schlägt die Prüfung auf Planet fehl. orbit wirft, und der Mond bleibt bei der Erde.
Die Exception wird in einer kleinen Hilfsfunktion abgefangen. Sie probiert die Umlaufbahn aus und sagt bei einer Ablehnung, warum:
static void tryOrbit(Orbiter orbiter, SpaceObject target) { try { orbiter.orbit(target); } catch (NotValidSpaceObjectException e) { System.out.println("Abgelehnt: " + e.getMessage()); }}static void TryOrbit(Orbiter orbiter, SpaceObject target){ try { orbiter.Orbit(target); } catch (NotValidSpaceObjectException e) { Console.WriteLine("Abgelehnt: " + e.Message); }}def try_orbit(orbiter, target): try: orbiter.orbit(target) except NotValidSpaceObjectError as e: print(f"Abgelehnt: {e}")function tryOrbit(orbiter, target) { try { orbiter.orbit(target); } catch (e) { if (!(e instanceof NotValidSpaceObjectError)) { throw e; } console.log(`Abgelehnt: ${e.message}`); }}catch hat in JavaScript keinen Typ in den Klammern: Es fängt jeden Fehler ab, auch einen aus einem Tippfehler im Code. Darum prüft tryOrbit mit instanceof. Eine abgelehnte Umlaufbahn gibt es aus, und jeden anderen Fehler wirft es mit throw e weiter.
Probier es aus
Wie viele umkreisen?
Der Mars versucht, die Erde zu umkreisen.
Was gibt das Programm aus?
function tryOrbit(orbiter, target) { try { orbiter.orbit(target); } catch (e) { if (!(e instanceof NotValidSpaceObjectError)) { throw e; } console.log(`Abgelehnt: ${e.message}`); }}
const sun = new Star("Sonne", 0, 0, 0, 333000);const earth = new Planet("Erde", 149.6, 0, 0, 1);const mars = new Planet("Mars", 227.9, 0, 0, 0.11);const moon = new Satellite("Mond", 150, 0, 0, 0.012);tryOrbit(earth, sun);tryOrbit(mars, earth);tryOrbit(moon, earth);console.log(`Um die Sonne: ${sun.getOrbiters().length}`);console.log(`Um die Erde: ${earth.getOrbiters().length}`);Der Mars besteht die Prüfung auf Star nicht und wird nirgends hinzugefügt. Die Hilfsfunktion fängt die Ablehnung ab, deshalb geht das Programm mit dem Mond weiter. Um die Sonne kreist nur die Erde, um die Erde nur der Mond.
Die Idee
Ein Schiff, das fliegt
Schiffe umkreisen nichts, sie fliegen von Objekt zu Objekt. Das ist ein anderer Vertrag:
interface Fly { void flyTo(SpaceObject destination) throws NotValidSpaceObjectException;}interface Fly{ void FlyTo(SpaceObject destination);}class Fly(ABC): @abstractmethod def fly_to(self, destination): pass// Der Vertrag Fly: Das Objekt hat eine Methode flyTo(destination), die es zu destination// bringt oder NotValidSpaceObjectError wirft.SpaceShip erbt von SpaceObject und hat eine Methode flyTo. Zu einem Stern kann es nicht fliegen. Zu allem anderen fliegt es und übernimmt die Koordinaten des Ziels:
@Overridepublic void flyTo(SpaceObject destination) throws NotValidSpaceObjectException { if (destination instanceof Star) { throw new NotValidSpaceObjectException(getName() + " kann nicht zu " + destination.getName() + " fliegen: Der Stern würde das Schiff verbrennen"); } moveTo(destination.getCoordinateX(), destination.getCoordinateY(), destination.getCoordinateZ()); System.out.println(getName() + " ist bei " + destination.getName() + " angekommen");}public void FlyTo(SpaceObject destination){ if (destination is Star) { throw new NotValidSpaceObjectException(Name + " kann nicht zu " + destination.Name + " fliegen: Der Stern würde das Schiff verbrennen"); } MoveTo(destination.CoordinateX, destination.CoordinateY, destination.CoordinateZ); Console.WriteLine(Name + " ist bei " + destination.Name + " angekommen");}def fly_to(self, destination): if isinstance(destination, Star): raise NotValidSpaceObjectError(f"{self.name} kann nicht zu {destination.name} fliegen: Der Stern würde das Schiff verbrennen") self._move_to(destination.coordinate_x, destination.coordinate_y, destination.coordinate_z) print(f"{self.name} ist bei {destination.name} angekommen")flyTo(destination) { if (destination instanceof Star) { throw new NotValidSpaceObjectError(`${this.name} kann nicht zu ${destination.name} fliegen: Der Stern würde das Schiff verbrennen`); } this._moveTo(destination.coordinateX, destination.coordinateY, destination.coordinateZ); console.log(`${this.name} ist bei ${destination.name} angekommen`);}SpaceShip ship = new SpaceShip("Wanderer", 149.6, 0, 0, 0);Planet mars = new Planet("Mars", 227.9, 0, 0, 0.11);Star sun = new Star("Sonne", 0, 0, 0, 333000);try { ship.flyTo(mars); ship.displayInfo(); ship.flyTo(sun); ship.displayInfo();} catch (NotValidSpaceObjectException e) { System.out.println("Abgelehnt: " + e.getMessage());}Wanderer ist bei Mars angekommenSchiff Wanderer: (227.9, 0.0, 0.0), Masse 0.00Abgelehnt: Wanderer kann nicht zu Sonne fliegen: Der Stern würde das Schiff verbrennenSpaceShip ship = new SpaceShip("Wanderer", 149.6, 0, 0, 0);Planet mars = new Planet("Mars", 227.9, 0, 0, 0.11);Star sun = new Star("Sonne", 0, 0, 0, 333000);try{ ship.FlyTo(mars); ship.DisplayInfo(); ship.FlyTo(sun); ship.DisplayInfo();}catch (NotValidSpaceObjectException e){ Console.WriteLine("Abgelehnt: " + e.Message);}Wanderer ist bei Mars angekommenSchiff Wanderer: (227.9, 0.0, 0.0), Masse 0.00Abgelehnt: Wanderer kann nicht zu Sonne fliegen: Der Stern würde das Schiff verbrennenship = SpaceShip("Wanderer", 149.6, 0, 0, 0)mars = Planet("Mars", 227.9, 0, 0, 0.11)sun = Star("Sonne", 0, 0, 0, 333000)try: ship.fly_to(mars) ship.display_info() ship.fly_to(sun) ship.display_info()except NotValidSpaceObjectError as e: print(f"Abgelehnt: {e}")Wanderer ist bei Mars angekommenSchiff Wanderer: (227.9, 0.0, 0.0), Masse 0.00Abgelehnt: Wanderer kann nicht zu Sonne fliegen: Der Stern würde das Schiff verbrennenconst ship = new SpaceShip("Wanderer", 149.6, 0, 0, 0);const mars = new Planet("Mars", 227.9, 0, 0, 0.11);const sun = new Star("Sonne", 0, 0, 0, 333000);try { ship.flyTo(mars); ship.displayInfo(); ship.flyTo(sun); ship.displayInfo();} catch (e) { if (!(e instanceof NotValidSpaceObjectError)) { throw e; } console.log(`Abgelehnt: ${e.message}`);}Wanderer ist bei Mars angekommenSchiff Wanderer: (227.9, 0.0, 0.0), Masse 0.00Abgelehnt: Wanderer kann nicht zu Sonne fliegen: Der Stern würde das Schiff verbrennenDas zweite displayInfo() läuft nicht: Die Exception springt zu catch.
Genauer, für Neugierige
extends nimmt nur eine Basisklasse. Ein Aufklärungssatellit, der auch fliegen kann, ist class Probe extends SpaceObject mit beiden Methoden, orbit und flyTo: Für Duck Typing reicht das.Probier es aus
Finde den Fehler
Der Mond umkreist die Sonne, und das soll er nicht. In welcher Zeile im orbit des Satelliten steckt der Fehler?
Wähle die Zeile mit dem Fehler.
OrbitableSpaceObject ist die Basisklasse von Planet und von Star. Die Prüfung lässt beide durch. Es muss target instanceof Planet heißen: Ein Satellit umkreist nur einen Planeten.
Übung
Das All im Code
Löse die Aufgaben in deinem Editor, mit den Klassen aus der Lektion.
1. Das Sonnensystem. Beschreibe die acht Planeten mit drei Arrays: Namen, Abstände von der Sonne (Millionen km) und Massen (Erdmassen). Erzeuge in einer Schleife jeden Planeten bei x = Abstand und lass ihn die Sonne umkreisen. Zeige danach alle Umkreisenden.
| Planet | Abstand | Masse |
|---|---|---|
| Merkur | 57,9 | 0,06 |
| Venus | 108,2 | 0,82 |
| Erde | 149,6 | 1 |
| Mars | 227,9 | 0,11 |
| Jupiter | 778,5 | 317,8 |
| Saturn | 1.432 | 95,2 |
| Uranus | 2.867 | 14,5 |
| Neptun | 4.515 | 17,1 |
Merkur umkreist SonneVenus umkreist SonneErde umkreist SonneMars umkreist SonneJupiter umkreist SonneSaturn umkreist SonneUranus umkreist SonneNeptun umkreist SonneUm Sonne kreisen 8 Planeten:Planet Merkur: (57.9, 0.0, 0.0), Masse 0.06Planet Venus: (108.2, 0.0, 0.0), Masse 0.82Planet Erde: (149.6, 0.0, 0.0), Masse 1.00Planet Mars: (227.9, 0.0, 0.0), Masse 0.11Planet Jupiter: (778.5, 0.0, 0.0), Masse 317.80Planet Saturn: (1432.0, 0.0, 0.0), Masse 95.20Planet Uranus: (2867.0, 0.0, 0.0), Masse 14.50Planet Neptun: (4515.0, 0.0, 0.0), Masse 17.102. Abstand. Schreibe function distance(a, b) mit dem Satz des Pythagoras in drei Dimensionen: die Wurzel aus der Summe der Quadrate der Unterschiede in x, y und z. Die Erde liegt bei (149,6; 0; 0), der Mars bei (0; 227,9; 0), der Mond bei (149,6; 0,4; 0), und die Sonne liegt im Ursprung.
Erde bis Mars: 272.6 Mio. kmErde bis Mond: 0.4 Mio. kmSonne bis Mars: 227.9 Mio. km3. Der ganze Baum. Ändere displayInfo so, dass der Stern auch seine Planeten zeigt und jeder Planet seine Satelliten, mit zwei Leerzeichen Einrückung pro Ebene. Tipp: ein Parameter für die Einrückung mit einem Standardwert, indent = "", damit der Aufruf auch ohne Argument geht. OrbitableSpaceObject überschreibt die Methode und ruft die der Basisklasse auf. Erde und Mars umkreisen die Sonne, der Mond umkreist die Erde, und Phobos umkreist den Mars.
Erde umkreist SonneMars umkreist SonneMond umkreist ErdePhobos umkreist MarsStern Sonne: (0.0, 0.0, 0.0), Masse 333000.00 Planet Erde: (149.6, 0.0, 0.0), Masse 1.00 Satellit Mond: (150.0, 0.0, 0.0), Masse 0.01 Planet Mars: (227.9, 0.0, 0.0), Masse 0.11 Satellit Phobos: (227.9, 0.0, 0.0), Masse 0.00Weitere Aufgaben
- Doppelter Versuch. Im Moment kann die Erde zweimal zu den Objekten hinzugefügt werden, die die Sonne umkreisen. Sorge dafür, dass ein zweiter Versuch
NotValidSpaceObjectErrorwirft. - Ein voller Stern. Füge einem Stern 11 Planeten hinzu und fange die Exception beim elften ab.
- Eine Sonde. Baue eine
Probe, die sowohl umkreist als auch fliegt (siehe „Genauer“ bei den Schiffen).
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: Interfaces ohne interface · Typprüfungen · Exceptions · Werfen und eigene Exceptions
- Aufgaben zum Thema: Wir bauen ein Spiel