SECTION(16, Tutorial 16)
m5_question(This tutorial shows you a practical example of
inheritance. The file TT(StarWars.sjs) is comprised of three classes:
CLSS(XWing), CLSS(TieFighter) and CLSS(StarWars). The first two
represent spacecraft from the two sides of the Star Wars films. The
class CLSS(StarWars) is the driver class and contains code for
executing a battle between the X-Wings and the Tie Fighters.)
m5_study(16.1)
m5_question(
POPEN
m4_begin_indent
NU()CLASS CLSS(XWing) EOL
BEGIN EOL
EOL
PD PRIVATE PROPERTY INT VARI(shields); EOL
PD PRIVATE PROPERTY INT VARI(weapon); EOL
PD PRIVATE PROPERTY BOOLEAN VARI(dead); EOL
EOL
PD CONSTRUCTOR CLSS(XWing)() EOL
PD BEGIN EOL
PD PD shields = NUMB(1000); EOL
PD PD weapon = NUMB(10); EOL
PD END EOL
EOL
PD METHOD INT FUNC(getWeapon)() EOL
PD BEGIN EOL
PD PD RETURN weapon; EOL
PD END EOL
PD METHOD BOOLEAN FUNC(isDead)() EOL
PD BEGIN EOL
PD PD RETURN dead; EOL
PD END EOL
PD METHOD VOID FUNC(hit)(INT VARI(damage)) EOL
PD BEGIN EOL
PD PD shields = shields - damage; EOL
PD PD IF (LT(shields,0)) EOL
PD PD THEN BEGIN EOL
PD PD PD SYSTEM_OUT_PRINTLN(STRI("BOOM!!!")); EOL
PD PD PD dead = TRUE; EOL
PD PD END EOL
PD END EOL
END EOL
EOL
CLASS CLSS(TieFighter) EOL
BEGIN EOL
EOL
PD PRIVATE PROPERTY INT VARI(shields); EOL
PD PRIVATE PROPERTY INT VARI(weapon); EOL
PD PRIVATE PROPERTY BOOLEAN VARI(dead); EOL
EOL
PD CONSTRUCTOR CLSS(TieFighter)() EOL
PD BEGIN EOL
PD PD shields = NUMB(500); EOL
PD PD weapon = NUMB(20); EOL
PD END EOL
EOL
PD METHOD INT FUNC(getWeapon)() EOL
PD BEGIN EOL
PD PD RETURN weapon; EOL
PD END EOL
PD METHOD BOOLEAN FUNC(isDead)() EOL
PD BEGIN EOL
PD PD RETURN dead; EOL
PD END EOL
PD METHOD VOID FUNC(hit)(INT VARI(damage)) EOL
PD BEGIN EOL
PD PD shields = shields - damage; EOL
PD PD IF (LT(shields,0)) EOL
PD PD THEN BEGIN EOL
PD PD PD SYSTEM_OUT_PRINTLN(STRI("BOOM!!!")); EOL
PD PD PD dead = TRUE; EOL
PD PD END EOL
PD END EOL
END EOL
EOL
CLASS CLSS(StarWars) EOL
BEGIN EOL
EOL
PD PRIVATE FUNCTION VOID FUNC(duel)(CLSS(XWing) VARI(x), CLSS(TieFighter) VARI(t)) EOL
PD BEGIN EOL
EOL
PD PD FUR (;;) EOL
PD PD BEGIN EOL
PD PD PD x.hit(t.getWeapon()); EOL
PD PD PD IF (x.isDead()) EOL
PD PD PD THEN BEGIN EOL
PD PD PD PD SYSTEM_OUT_PRINTLN(STRI("X-Wing is dead")); EOL
PD PD PD PD BREAK; EOL
PD PD PD END EOL
PD PD PD t.hit(x.getWeapon()); EOL
PD PD PD IF (t.isDead()) EOL
PD PD PD THEN BEGIN EOL
PD PD PD PD SYSTEM_OUT_PRINTLN(STRI("Tie Fighter is dead")); EOL
PD PD PD PD BREAK; EOL
PD PD PD END EOL
PD PD END EOL
EOL
PD END EOL
EOL
PD PRIVATE FUNCTION VOID FUNC(battle)(CLSS(XWing)[] VARI(good), CLSS(TieFighter)[] VARI(evil)) EOL
PD BEGIN EOL
EOL
PD PD VAR INT VARI(g)PD PD PD = NUMB(0); EOL
PD PD VAR INT VARI(e)PD PD PD = NUMB(0); EOL
PD PD VAR INT VARI(goodDeaths) = NUMB(0); EOL
PD PD VAR INT VARI(evilDeaths) = NUMB(0); EOL
EOL
PD PD WHILE (LT(g,good.length) AND LT(e,evil.length)) EOL
PD PD BEGIN EOL
PD PD PD SYSTEM_OUT_PRINTLN(STRI("battling X-Wing HASH") + g + STRI(" versus Tie Fighter HASH") + e); EOL
PD PD PD duel(good[g],evil[e]); EOL
PD PD PD IF (good[g].isDead()) EOL
PD PD PD THEN BEGIN EOL
PD PD PD PD g = g + NUMB(1); EOL
PD PD PD PD goodDeaths = goodDeaths + NUMB(1); EOL
PD PD PD END EOL
PD PD PD IF (evil[e].isDead()) EOL
PD PD PD THEN BEGIN EOL
PD PD PD PD e = e + NUMB(1); EOL
PD PD PD PD evilDeaths = evilDeaths + NUMB(1); EOL
PD PD PD END EOL
PD PD END EOL
EOL
PD PD VAR INT VARI(finalGood) = good.length - goodDeaths; EOL
PD PD VAR INT VARI(finalEvil) = evil.length - evilDeaths; EOL
EOL
PD PD SYSTEM_OUT_PRINTLN(); EOL
PD PD SYSTEM_OUT_PRINTLN(STRI("Battle Report: X-Wings Tie Fighters")); EOL
PD PD SYSTEM_OUT_PRINTLN(STRI("----------------------------------------------")); EOL
PD PD SYSTEM_OUT_PRINTLN(); EOL
PD PD SYSTEM_OUT_PRINTLN(STRI("Initial ships:") + good.length + STRI(" ") + evil.length); EOL
PD PD SYSTEM_OUT_PRINTLN(); EOL
PD PD SYSTEM_OUT_PRINTLN(STRI("Killed ships:") + goodDeaths + STRI(" ") + evilDeaths); EOL
PD PD SYSTEM_OUT_PRINTLN(); EOL
PD PD SYSTEM_OUT_PRINTLN(STRI("Final ships:")PD + finalGood + STRI(" ") + finalEvil); EOL
PD PD SYSTEM_OUT_PRINTLN(); EOL
PD PD IF (GT(finalGood,finalEvil)) EOL
PD PD THEN BEGIN EOL
PD PD PD SYSTEM_OUT_PRINTLN(STRI("The rebel alliance is victorious!")); EOL
PD PD END EOL
PD PD ELSE BEGIN EOL
PD PD PD SYSTEM_OUT_PRINTLN(STRI("The dark side has conquered!")); EOL
PD PD END EOL
PD PD SYSTEM_OUT_PRINTLN(); EOL
PD END EOL
EOL
PD BEGIN_MAIN EOL
EOL
PD PD COMM(// defines the goodies array) EOL
PD PD VAR CLSS(XWing)[] VARI(goodies) = NEW CLSS(XWing)[3]; EOL
EOL
PD PD COMM(// initialises the elements of the goodies array) EOL
PD PD FUR (VAR INT VARI(i)=NUMB(0); LT(i,goodies.length); i = i + NUMB(1)) EOL
PD PD BEGIN EOL
PD PD PD goodies[i] = NEW CLSS(XWing)(); EOL
PD PD END EOL
EOL
PD PD COMM(// defines the baddies array) EOL
PD PD VAR CLSS(TieFighter)[] VARI(baddies) = NEW CLSS(TieFighter)[3]; EOL
EOL
PD PD COMM(// initialises the elements of the baddies array) EOL
PD PD FUR (VAR INT VARI(i)=NUMB(0); LT(i,baddies.length); i=i+NUMB(1)) EOL
PD PD BEGIN EOL
PD PD PD baddies[i] = NEW CLSS(TieFighter)(); EOL
PD PD END EOL
EOL
PD PD battle(goodies,baddies); EOL
EOL
PD END_MAIN EOL
END EOL
m4_end_indent
)
m5_question(BO(Question 16.2:) Compile and run this file to see
the battle between the X-Wings and the Tie Fighters unfold.)
m5_question(BO(Question 16.3:) If you look at the Java code for
the CLSS(XWing) and CLSS(TieFighter) classes you will notice that they are
almost identical: They have the same methods and properties, the only
difference is that the CLSS(XWing) objects are initialised with a
different value for their shields and weapon properties to the
CLSS(TieFighter) objects.)
m5_question(The next few questions will guide you through the process
of using inheritance to eliminate this unnecessary duplication of
code. A new class called CLSS(SpaceShip) will be created and all of the
code that is common to CLSS(XWing) and CLSS(TieFighter) will be moved into
this class. The CLSS(XWing) and CLSS(TieFighter) classes will then be
modified so that they both inherit from CLSS(SpaceShip).)
m5_question(BO(Question 16.4:) The first step in this process is
to create the outer shell of the CLSS(SpaceShip) class, which you should now
type in:
m4_begin_indent
NU()CLASS CLSS(SpaceShip) EOL
BEGIN EOL
END EOL
m4_end_indent
)
m5_question(BO(Question 16.5:) Move the properties TT(shields),
TT(weapon) and TT(dead) out of the CLSS(XWing) and CLSS(TieFighter)
classes and into the CLSS(SpaceShip) class. You must change the privacy
status of the properties from EM(private) to EM(protected). The
protected modifier was invented as an intermediate level of privacy
between public and private. Like private, it allows visibility to the
same class in which the method or property was defined, but unlike
private it also allows visibility to subclasses of the class in which
the method or property was defined.)
m5_question(BO(Question 16.6:) Move the three methods
TT(getWeapon), TT(isDead) and TT(hit) out of the CLSS(XWing) and
CLSS(TieFighter) classses and into the CLSS(SpaceShip) class. At this
point, the CLSS(XWing) and CLSS(TieFighter) classes should contain nothing
but a constructor.)
m5_question(BO(Question 16.7:) Finally, add the EM(extends)
keyword to the first line of the CLSS(XWing) and CLSS(TieFighter) classes:
m4_begin_indent
NU()CLASS CLSS(XWing) EXTENDS CLSS(SpaceShip) EOL
m4_end_indent
NU()and
m4_begin_indent
NU()CLASS CLSS(TieFighter) EXTENDS CLSS(SpaceShip) EOL
m4_end_indent
)
m5_question(BO(Question 16.8:) Compile and run your program again,
making sure that it produces the same results now that it is using
inheritance.)
m5_question(BO(Question 16.9:) The CLSS(SpaceShip) class is a
superclass of both CLSS(XWing) and CLSS(TieFighter) containing everything
that X-Wings and Tie Fighters contain in common. Because the role of
the CLSS(SpaceShip) class is simply to hold these commonalities, we might
choose to label the class with the EM(abstract) keyword:
m4_begin_indent
NU()ABSTRACT CLASS CLSS(SpaceShip) EOL
m4_end_indent
NU()This prevents us from creating instances of the CLSS(SpaceShip)
class. Without the abstract modifier, we could happily create a NEW
TT(CLSS(SpaceShip)()), which would be an object that is not an X-Wing,
nor a Tie Fighter, but just a vague "space ship". If we consider this
to be a logical mistake then we can use abstract to prevent such calls
to the CLSS(SpaceShip) constructor. Change the class CLSS(SpaceShip)
to be abstract and observe how the compiler will not accept any lines
of the form:
m4_begin_indent
NU()VAR CLSS(SpaceShip) VARI(s) = NEW CLSS(SpaceShip)(); COMM(// compiler error) EOL
m4_end_indent
NU()Remove the ABSTRACT keyword and notice how the compiler will then
allow this line to compile.
)