6. Interfaces Lesson¶
Introduction to Interfaces¶
Introduction to Interfaces
Note
Activity objective: Show the benefits of interfaces at a high level. We want students to consider when it is appropriate to use an interface.
Interfaces in the Real World
If we swap out one specific device / object with another that shares the same interface, we can still use the new device even though it likely works differently. We are able to do this because we are familiar with the interface:
Motor Vehicles and Humans
Phone Dial Pads / Screens and Humans
Remote Controls and Humans
The same is true when two hardware devices need to interact:
ATMs and Debit Cards
Computers and USB Devices
etc.
This same idea can be applied to a software system (or systems) to let different parts interact with each other.
Interfaces in Software
Scenario: Disparate Classes, Common Action
We have Java code that uses an object of a particular class to perform some action or actions using the object, and we need to update the code to also be able to use an object of some other class to perform the same kind of action or actions using that object. The classes for these objects each perform the action in their own way.
Goal:
Setup our code so that whenever it switches between using these objects to perform the action, the code outside those object’s classes does not need to be updated.
Java Interfaces:
An interface makes classes plug an play (polymorphism). Just like if you swap out your car, you don’t want to have to relearn how to drive.
Interfaces allow us to remove dependencies between classes and make our code easier to update in the future.
When to Use:
Multiple disparate classes that share a common action but are otherwise unrelated (disparate) are good candidates for this technique.
Tip
Think of the common action as a high level action that will work differently on different devices.
For example: A car “moves forward” (high level action) when you press the gas pedal. However, older cars work differently from new cars, electric cars work differently from gas cars, etc.
Group Activity
Come up with an example involving two classes and a common action that meet the following criteria:
The classes are disparate (for this activity, let’s have NO overlap).
The classes contain a common action (method) that can be performed on either kind of object, even though the classes are disparate.
The common action should be a high level action. The action should not be done the same way for each class.
Create an interface to describe the common action.
Deliverables:
A UML diagram that shows the two classes, the interface, and the relationships between all three (arrows).
A short justification describing how the implemention of the common action (method) is different but still accomplishes the common goal.
The Drawable Interface¶
The Drawable Interface
Note
Some parts of this activity contain solutions. To show the solutions, you will need to toggle “Show Solutions” above.
Note
Activity objective: Show the benefits of interfaces using an example we can refactor.
Step 1: Write out disparate classes along with the main method that calls a method to draw each (name the draw method differently). The draw methods will need to be in the driver class for the first step.
Step 2: Show how we can refactor the code and put the draw method in each class and then adjust the main method.
Step 3: Add an interface and show the resulting UML diagram. The classes/relationships have changed. However, the main method is so much cleaner and won’t need to be modified later.
Part 1: Exploring the Problem
UML - Version 1
Consider the UML Diagram below and answer the following on your exit tickets:
Would you consider
Tree,Airplane, andPersonto be disparate classes?Do they share a common action?
Is the common action implemented the exact same way?
UML - Version 2
The common action “Draw” can be added to each class using an identical method signature:
UML - Version 3
Now, imagine we want to be able to draw many different objects of each type. We might create methods like this:
Discussion
Answer the following on your exit ticket:
Keeping the same structure as the existing code, what steps
would we need to take to add another class, Flower, that
can be drawn? Assume that the Flower class has two
methods: drawStem and drawPetals and that you would
need to call both to draw the entire flower. We also want a
method that allows us to draw many flowers at once.
You can answer by describing what you would need to do or by drawing a UML diagram.
Post-Discussion UML
What is tedious/error-prone about this process? What if we needed to add hundreds of classes that can be drawn?
Redundant Code
Let’s take a minute to consider the methods inside of the
Utility class. The drawFlowers method probably
looks something like this:
public static void drawFlowers(Flower[] flowers) {
for (Flower currentFlower: flowers) {
currentFlower.draw();
} // for
} // drawFlowers
On your exit tickets, answer the following questions:
How is
drawTreesdifferent fromdrawFlowers?How is
drawAirplanesdifferent fromdrawFlowers?Is there redundancy between these methods?
Thinking Bigger
Having to add a method to Utility every time we add a new
class (like Flower) is the equivalent of having to learn
to drive all over again if you buy a new car. We have to do this
because our classes do not have a common interface (even though
they all contain the same method).
Two changes doesn’t seem like a big deal at first, but imagine a larger code base with more dependencies. You don’t want to be worried that every change you make may introduce bugs in other classes and you certainly don’t want to be checking all dependent code for potential issues.
Part 2: Incorporating the Interface
How do Interfaces help?
Remember the goals of using interfaces:
Implementing classes should be plug and play
Reduce dependencies
Question
Answer the following on your exit ticket:
How could we incorporate an interface into this code?
What would you call the new interface?
What method(s) would need to be in the interface?
Which classes would implement the interface?
UML Comparison
What is better about the version of this code that contains the interface? Write your answer on your exit ticket.
Solution
There is only one dependency and fewer methods in Utility. The
Utility class will now work with all types that implement Drawable.
Discussion
Question
Answer the question below on your exit ticket:
With the new structure that incorporates the Drawable
interface, what would we need to do to add another class,
Flower, that can be drawn?
Updated UML
Part 2.5: Memory Map: Calling the drawAll Method
On your exit tickets, write out the code snippet for main
shown below, then draw a memory map that depicts what memory
looks like after all the lines in the main method execute:
1public static void drawAll(Drawable[] objs) {
2 for (Drawable obj: objs) {
3 obj.draw();
4 } // for
5} // for
1public static void main(String[] args) {
2
3 Drawable[] objects = new Drawable[2];
4
5} // main
1public static void drawAll(Drawable[] objs) {
2 for (Drawable obj: objs) {
3 obj.draw();
4 } // for
5} // for
1public static void main(String[] args) {
2
3 Drawable[] objects = new Drawable[2];
4 objects[0] = new Tree(12, Color.GRAY);
5 objects[1] = new Person(Color.GREEN, Color.GRAY);
6
7} // main
1public static void drawAll(Drawable[] objs) {
2 for (Drawable obj: objs) {
3 obj.draw();
4 } // for
5} // for
1public static void main(String[] args) {
2
3 Drawable[] objects = new Drawable[2];
4 objects[0] = new Tree(12, Color.GRAY);
5 objects[1] = new Person(Color.GREEN, Color.GRAY);
6
7 // What does memory look like when inside drawAll but
8 // just before it executes its first line of code?
9 Utility.drawAll(objects);
10
11} // main
1public static void drawAll(Drawable[] objs) {
2 for (Drawable obj: objs) {
3 obj.draw();
4 } // for
5} // for
1public static void main(String[] args) {
2
3 Drawable[] objects = new Drawable[2];
4 objects[0] = new Tree(12, Color.GRAY);
5 objects[1] = new Person(Color.GREEN, Color.GRAY);
6
7 // What does memory look like when inside drawAll and
8 // just before the call to draw() exeutes (first iteration)?
9 Utility.drawAll(objects);
10
11} // main
What is the data type of the
objvariable?Is the value of
objequal tonull?If not
null, what is the data type of the object thatobjrefers to?What class defines the body of the
draw()method being called viaobj?
Part 3: Compatibility
Imagine the code in each group is found in the main method
of a Driver class.
For each numbered block of code, write on your exit tickets whether or not the code will compile. Explain your answer for each.
Group 1
Drawable d = new Person(Color.BLUE, Color.BLUE); d.draw();
Drawable d = new Person(Color.BLUE, Color.BLUE); d.getEyeColor();
Drawable d = new Person(Color.BLUE, Color.BLUE); Utility.drawIt(d);
Group 2
Utility.drawIt(new Person(Color.BLUE, Color.BLUE));
Person bob = new Person(Color.BLUE, Color.BLUE); System.out.println(bob.getHaircolor());
Airplane plane = new Drawable();
Group 3
Drawable tree = new Tree(5, Color.GREEN); tree.grow(7);
Tree tree = new Tree(5, Color.GREEN); tree.draw();
Drawable device = new Scanner(System.in); device.draw();
Group 4
Utility.drawIt(new Scanner(System.in));
Tree tree = new Tree(5, Color.GREEN); Drawable d = tree;
Solutions
Yes:
draw()is defined in theDrawableinterface andPersonis compatible withDrawablesince it implements it.No: The compiler only looks at the type of the variable (
Drawable), which determines which methods can be called. The interface does not containgetEyeColor(), so it is not allowed..Yes: The
drawItmethod takes in a reference of typeDrawable. Any compatible type can be passed in.Yes: The
drawItmethod takes in a reference of typeDrawable. Any compatible type can be passed in.Yes: The variable type is
Person, so unique person methods are accessible.No: Interfaces cannot be instantiated using the
newkeyword.No:
growis unique to theTreeclass and is not visible when using aDrawablereference sinceDrawabledoes not have agrowmethod.Yes:
Treeimplements the interface, so it possesses thedraw()method.No: The
Drawableis not compatible withScannersinceScannerdoes not implement the interface.No: The
Drawableis not compatible withScannersinceScannerdoes not implement the interface.Yes: Assigning a specific object to a compatible type (class or interface) is always allowed.
Part 4: Bulk Draw
Download Source Code (Instructors)
Note
The starter code contains the same interface and implementing
classes. It also comes with a Driver program (containing a main method).
While the implementing classes do implement the interface and have
a draw method, they may not have all of the methods found
in the UML above. Any differences are not substantial and will
not affect your ability to complete the last two parts of the
lesson.
Execute the command below to download and extract the files:
sh -c "$(curl -fsSL https://cs1302book.com/_bundle/cs1302-interface-lesson.sh)"
- downloading cs1302-interface-lesson bundle...
- verifying integrity of downloaded files using sha256sum...
- extracting downloaded archive...
- removing intermediate files...
subdirectory cs1302-interface-lesson successfully created
Change to the cs1302-interface-lesson directory that was created using
cd, then look at the files that were bundled as part of the
starter code using tree.
Download Source Code (Students)
Note
The starter code contains the same interface and implementing
classes. It also comes with a Driver program (containing a main method).
While the implementing classes do implement the interface and have
a draw method, they may not have all of the methods found
in the UML above. Any differences are not substantial and will
not affect your ability to complete the last two parts of the
lesson.
interface1302
- downloading cs1302-interface-lesson bundle...
- verifying integrity of downloaded files using sha256sum...
- extracting downloaded archive...
- removing intermediate files...
subdirectory cs1302-interface-lesson successfully created
Change to the cs1302-interface-lesson directory that was created using
cd, then look at the files that were bundled as part of the
starter code using tree.
Interpreter Script
Notice the file called compile_and_run.sh located directly inside of
cs1302-interface-lesson. This file contains the appropriate compilation
commands for each of the files in our starter code. Instead of typing each
command manually, we can run this file to clean out bin, compile the
code, and run our driver. You can find more information on compiler
scripts in the assigned textbook reading on the topic.
Go ahead and run the file now. You won’t see any output because our
Driver doesn’t contain any print statements (yet).
./compile_and_run.sh
Bulk Draw (Activity)
In the main of the Driver class, we have created an array
of Drawable references and assigned each index a valid/compatible
object.
Implement the drawAll method in Utility.java and then
call the method from main using the existing Drawable array.
When you are finished, use the script
(compile_and_run.sh) to compile and run your code instead
of manually typing out the commands!
Now, you should see some output!
Part 5: Adding an Implementing Class
Planning for a new class (No Laptops)
Discuss and then draw a UML diagram for a new class to add to the code that meets the following criteria:
has minimal overlap with the existing classes (disparate);
has at least two instance variables;
has at least two instance methods (excluding getters/setters);
properly implements the
Drawableinterface.
Implement the new class (Laptops)
Create the
.javafor your new class and implement it in that file. In addition to everything else, be sure to not forget to includeimplementsand the method override.Update the compile script to compile the new class.
Make sure that your new class compiles using the script before continuing to the next part.
Use the new class (Laptops)
Add an instance of the new class to the
Drawablearray in themainmethod.Call
drawAllon the updated array containing the new type of object.
Write on your exit ticket: How did the code in the Utility
class have to change to accommodate this new class?