
Library / Media
Learning goals
In this activity, you will learn how you can use Java interfaces to create polymorphism, allowing objects within the same List
to have different behaviors. After completing this activity you should be able to:
- Create a new interface
- Write classes that implement your interface
- Make different classes under the same interface display different behavior
- Start to recognize polymorphism and the problems it solves
What problem are you solving?
Run the LibraryMain
class. Observe how the program behaves. You will preserve that functionality as you work on this activity, adding new features without altering existing ones!
Here’s our problem: we want our library to be able to hold and check out things other than books. For now we are adding videos; in the future, we might add even more kinds of items. This goal collides with our existing code, posing some vexing questions:
- Books and videos do not have the same metadata. For example, books have authors while videos have directors. How do we have different fields for different items??
- We are going to have different rules — and thus different code — for checking out books versus videos. How do we keep the
checkIn
/checkout
code from getting too complicated to read and maintain?? - The code in
LibraryMain
specifically mentionsBook
in many places, most crucially in the variouslibrary
variables whose type isList<Book>
. Can we have something like aList<Book or Video or maybe other stuff too>
??
A terrible solution
Here’s a really bad idea: we could expand the Book
class to turn it into BookOrVideo
, and stuff everything we need for both books and videos into one class. We are not going to do this, but think about it for a moment:
- Books and videos do not have the same metadata, so our terrible
BookOrVideo
class would need instance variables for any information we might want about either a book or a video. We would have to leave some of those fieldsnull
for cetain item types. That means always carefully avoiding using the wrong fields depending on the type of item, so that for example we never have an object with an author and a director. - Our
checkOut
andcheckIn
methods would grow long and complicated, since they have to handle rules for books and videos in the same place — and those methods would only grow longer if we add yet more types of media. - How do we know whether a
BookOrVideo
object truly represents a book or a video?
It gets messy fast. Fortunately, there is a better way.
Create an interface
We are going to create our first interface, called Media
.
- Create a new interface the same way you would create a new class: right click on the package folder, create a new file named
Media.java
, then use the wordinterface
instead ofclass
in the source code.
Add three methods to the interface:
-
getTitle
, which has no parameters and has the return typeString
-
checkOut
, which has no parameters and has the return typeboolean
-
checkIn
, which has no parameters and has the return typeboolean
Remember from the reading: when creating an interface, you do not provide an actual implementation of the method. Put a semicolon after the method signature.
Congratulations! You have an interface.
An interface in Java is a description of something that multiple different classes have in common. In this case, what we are saying is, “There is something called Media
in our world. Many different classes could all be kinds of Media
. What they all have in common are that they have titles, and you can check them out and check them in.”
Java syntax
What it’s called
What it means
interface Media { … }
- interface declaration
- declare an interface
“In our world, Media
is one kind of thing that can exist. Many different classes could be a kind of Media
.”
interface Media { … boolean checkOut(); … }
- abstract method declaration
- declare an abstract method
“Every class that is a kind of Media
must have its out checkOut
method that takes no parameters and returns a boolean. We aren’t specifying how that method words; there is no implementation here. We are just saying that this method must exist on any class that is a kind of Media
.”
This interface directly answers each of the vexing questions questions above:
- How do we have different fields for different items??
-
Many different classes can all be a kind of
Media
, and each one can have different instance variables!
-
How do we keep the
checkIn
/checkout
code from getting too complicated to read and maintain?? -
Each different class can have its own separate implementation of those methods.
-
Can we have something like a
List<Book or Video or maybe other stuff too>
?? -
Yes! That is what we are going to achieve in this activity.
Implement your interface
For your next task, you will both make the Book
class implement the Media
interface and create a new class, Video
, which implements this interface.
-
First, open up
Book.java
. In the class declaration line, after the name of the class, add:implements Media
Rerun your program and make sure it still works. If you’ve completed Task 1 and added the implements keyword correctly, you should have no errors. The existing
Book
class already matches theMedia
interface you created. -
Create a new Java class
Video
. YourVideo
class represents video media that the library would like to start stocking—hurray! However, library policy forVideo
is going to be different than policy for Books: the library plans to buy multiple copies of each Video item it will stock. Implement the following behavior:-
The
Video
class must implement the Media interface. -
Video
items are tracked by the following:- Title
- Director
- Number of copies the library owns
The constructor for
Video
must set all of these values. -
To check out a video from the library, you should check how many copies of the video are still available. Checking out should only be successful (return true) if there is at least one copy of the Video still available. A successful checkout removes one copy from being available.
-
To check in a video from the library, you should confirm that the library is missing at least one of the copies that they own. If the library already has all of its copies of that Video item, the check in should fail (returns false). A successful check-in adds one copy to the total available.
-
The Video class must implement a
toString
method that returns the title, director, and number of copies available for loan. - The
Video
class must implement agetTitle()
method that returns the title of the video.
-
-
Once you have an error-free
Video
class, openLibraryMain
and make it compatible with allMedia
objects. There are five TODOs commented throughout the class. Change the code underneath each of these so that it works withMedia
objects in general, not justBook
objects.- Don’t forget to add new
Video
objects to yourlibrary
List
! You can base your additions off of the sample code that adds newBook
objects.
- Don’t forget to add new
-
Rerun
LibraryMain
. You’ve implemented an interface and two classes that use it! Do you see the differences you expect in howBooks
andVideo
are handled?
Java syntax
What it’s called
What it means
class Book implements Media { … }
- Media is a supertype of Book
- Book is a subtype of Media
“Book
is a kind of Media
. Every Book
object is a Media
object.”
@Override public boolean checkOut() { … }
- method override
- (In Java, this
@
syntax is called an annotation.@Test
is another example.)
“I think that this checkOut
method matched a method in a supertype. Please give me an error if it doesn’t!”
Did you notice the magic? You might have missed the magic!
Your LibraryMain
should now have a little code that looks something like this:
for(Media mediaItem : library) {
if(mediaItem.getTitle().equalsIgnoreCase(title)) {
return mediaItem.checkOut();
}
}
Don’t worry if you used a different variable name for mediaItem
. That’s fine. Focus on this part:
for(Media mediaItem : library) { if(mediaItem.getTitle().equalsIgnoreCase(title)) { return mediaItem.checkOut(); } }
Here is the question: what code runs when that method is called? The answer is that you can’t know. You don’t have enough information to answer that question. Why? Because you have to know which specific subtype of Media
this particular mediaItem
is. It could be a Book
or a Video
— the library contains both! — and depending on which one it is, Java will run a different implementation of checkOut
. This magic is called polymorphism.
Polymorphism is when one variable in a program can refer to many different types of values, and the same function / method call in the same spot in the code can thus cause different code to run at different times. (Computer scientists quibble about the exact definition of polymorphism and which specific things count, but that is the gist of it.)
The word comes from Greek: poly many + morphē form.
In our code, polymorphism is what allows the same library code to manage many different kinds of items.
Bonus challenges
These are some optional additional challenges that you can use to practice using interfaces.
-
Add a new media type of your choice to the library: create a class for that media that implements the
Media
interface, and set some rules and unique behavior for how check in or check out works. Some ideas:- Rare manuscripts: cannot be checked in or out, but should always be shown as available (for supervised research!)
- Digital articles: can be checked out limitless times, because they’re available online, never need to be checked in, always available
-
Add a new command to
LibraryMain
and corresponding code in your interface and classes that allows users to do something other than check in and check out books. Some ideas:- Preview: This would allow users to see a short description of a title before checking it out.
- Hold: This would set an item on hold so that it cannot be checked out.
We didn’t ask you to type this, but VS Code might have inserted it for you. It’s a safety check, and a good idea. If, for example, you misspell the method as
chekOut
, you will get a helpful error message.