RU beehive logo ITEC dept promo banner
ITEC 120
2007fall
ibarland,
jdymacek

homeinfoexamslectureslabshws
RecipeLawsliessyntaxjava.lang docsjava.util docs

lab15a
inheritance
to avoid repeated code

We will make one new class — Describable — which includes the code repeated of Room and Treasure. Then Room and Treasure will extend Describable.

  1. Create class Describable, with fields name and description, along with getters (and setters, if any).
    (You can copy these out of one of the two original classes, of course.)
  2. Should Describable be declared abstract?
    Yes! -- we'll never have an object which is Describable without being something more specific (that is, w/o being a subclass of Describable). (just as we didn't have an Animal which wasn't some subclass of Animal, but we did have Dogs which weren't subclasses of Dog.)
  3. Write a constructor for Describable. (The job of the constructor is to initialize all the fields. That responsibility doesn't disappear just because the class is abstract, or will be inherited from.)
  4. Modify Treasure and Room:
    1. Remove those fields and methods from Treasure and Room.
    2. Have each of these two classes extend Describable.
    3. Modify the constructors so that their first line is a call to Describable's constructor:
      super(  ) .
              
    At this point, your code should compile and behave exactly the same as before (even though there's less of it). Note that if your Treasure had accessed its (private) fields directly instead of using the getters/setters, things have now broken a bit -- the fields are in a different class (Describable), and if they're private then class Treasure can't access them! There are three solutions, from worst to best:
    1. Make the fields in Describable public. Yech.
    2. Make the fields in Describable protected. This is a new privacy setting which means “can be accessed by this class and anybody who extends this class”. This is reasonable, and is often done.
    3. However I still prefer:
    4. Make the fields private, and have a public getter that even other Treasure methods use. (If you want a setter which isn't public, you can make that protected.)
  5. Challenge: More troubling than the repeated fields and getters, were some static methods dealing for list of Rooms/Treasures: treasureListToString and roomListToString were repeated code.

    You would certainly think that you just change the parameter-type from LinkedList<Room> to LinkedList<Describable>, and then your function can be passed either a List<Room> or a List<Treasure>. Alas: it's not quite so simple1, when you have collections of items. You need to give the signature as

      public <T extends Describable> String DescribablesToString( java.util.List<T> items )
          
    That is, the input is a list of some type T, where we may not know exactly what T is at the moment, but we do know that T extends Describable. (Think of this as “a list of Describables, where everything in the list is the same type.”2.)

    Note that this is a new syntax — up til now, the angle-brackets were always part of some type's name. Here, the angle-brackets before the signature are extra type-information, to appease Java's type-checking. It's worth pondering, every now and then, how much Java's type system helps us by catching errors early, vs. gets makes us go through contortions to do what we want. Tomorrow's lecture on the command pattern raises similar issues.

    Once you have this method describablesToString, you can collapse TextIO's two methods selectRoom and selectTreasure into one. Run your program, to make sure everything works the same as before (with even less code).

  6. Optional; this step requires that you have already added the GuiIO class to your project, as in hw-ec05.

    Make a interface IO. It declares methods display, prompt, etc. each of them as an abstract method (a declaration without a body):

    public abstract String prompt( String msg )
    

    Once you have the interface both TextIO and GuiIO will implement IO. Finally, in Explorer instead of a local variable whose declared type is TextIO, that variable's declared type should be IO. This variable will be initialized with (either) a new GuiIO() or a new TextIO().
    (This time, the refactoring it doesn't eliminate any repeated code, but it helps sets us up for any future methods which want to be given an IO but don't care which type they get.)


1

Why not? If a Treasure is-a Describable, then List<Treasure> is-a List<Describable>, right? Wrong! There is something you can do with a List<Describable>, that you can't do with a List<Treasure>: add a Room to it.

We say that lists are contravariant, if “A extends B” doesn't imply “list-of-A extends list-of-B”.

     

2Note that “LinkedList<Describable>” refers to a list which may contain both Rooms and Treasures at the same time. But that's not what we're passing in, which is why the extra “question-mark” notation is needed.      

homeinfoexamslectureslabshws
RecipeLawsliessyntaxjava.lang docsjava.util docs


©2007, Ian Barland, Radford University
Last modified 2007.Dec.05 (Wed)
Please mail any suggestions
(incl. typos, broken links)
to iba�rlandrad�ford.edu
Powered by PLT Scheme