6: Inheritance & Algorithms

We introduce our first complex algorithms and start to pull back the scaffolding a bit. Students will get their first real experience designing aggregate objects with encapsulated properties.

Learning Targets

  • I can secure my class variables with encapsulation.

  • I can create a constructor to initialize an object.

  • I can override a parent method.

  • I can build unit tests for all methods in an aggregate object.

Inheritance

Keep it DRY and OOP-y

DRY stands for Don't Repeat Yourself. So far, that's meant that if you need to repeat a bit of code, you make a loop instead of sloppily copying and pasting the same commands a few times. Now we're seeing that OOP, or Object-Oriented Programming, has was to build classes off of one another. That means we can avoid repeating (aka DRY code) by using inheritance.

Abstract Classes

Polymorphism Practice

Polymorphism is my favorite CS term because it sounds so much fancier than it really is (sort of a theme here). In class we'll build an abstract class called Shape with some encaspulated instance variables like length and width, abstract methods like .area(). Then we'll inherit from those methods when we create types of shapes like Circle, Rectangle, Triangle and so on. Let's look closer at why this is an example of inheritance and polymorphism.

Why this is smart, object-oriented programming

Creating a parent class called Shape that all your shapes will inherit means that the common properties and functions can live in one place. If new features or changes needed to happen across all the elements in your app, you would have a logical place to check.

But why do we declare abstract methods?

Let's take a look at a shortened Shape class:

class Shape {
    
    // a single example encaspulated instance variable
    private float length;
    
    // accessor method
    public float length(){
        // using this. is not required but helpful when writing
        return this.length; 
    
    // mutator method
    public void length(float length){
        // now using this. is required to tell the local and instance var apart
        this.length = length;

    // example abstract method. Each shape will need to make or "implement" 
    pubilc abstract float area();
        
}

All the encapsulation shown between lines 3 - 14 should be familiar by now. Seek additional practice including your teacher's office hours if not. The cool new thing here is line 17. Because the parent is declaring this method, all its children (i.e class Circle extends Shape { )will have to build their own area method. The Circle class will return 3.14 * (length * length); for its area() implementation.

So how exactly is this business "polymorphic?"

Because all of my app's shapes will have a common parent, I can create a collection of Shape like: ArrayList<Shape> myShapes = new ArrayList<>();

That allows me to to loop through the whole collection and report out their areas:

for (Shape x : myShapes) {
    System.out.println("This shape's area is: " + x.area() + " cm2");
}

Multiple Inheritance?

What if I wanted to build a huge space game with thousands of types of ships. I'd make rules for cargo ships and warships. There may be times when I want multiple inheritances to be applied. Well there are some limits here in Java. You can have multiple vertical levels, like Ship --> Warship --> Battleship but a single ship can't inherit from two places simultaneously. Instead, there are Interfaces.

Elevens

Please download the guide to this old project from CollegeBoard.

Elevens 1

Let's create a simple Card object and test its encapsulated properties.

/**
 * This is a class that tests the Card class.
 */
public class CardTester {

	/**
	 * The main method in this class checks the Card operations for consistency.
	 *	@param args is not used.
	 */
	public static void main(String[] args) {
		/* *** TO BE IMPLEMENTED IN ACTIVITY 1 *** */
	}
}

Elevens 2

Now we'll build our aggregate object, the Deck.

/**
 * This is a class that tests the Deck class.
 */
public class DeckTester {

	/**
	 * The main method in this class checks the Deck operations for consistency.
	 *	@param args is not used.
	 */
	public static void main(String[] args) {
		/* *** TO BE IMPLEMENTED IN ACTIVITY 2 *** */
	}
}

Elevens 3: Shuffling Algorithm

This algorithm uses a lot of structures we'll see when we have to start sorting items rather than shuffling. The problem with a perfect shuffle is that after 4 passes, all the cards are back in the original order.

/**
 * This class provides a convenient way to test shuffling methods.
 */
public class Shuffler {

	/**
	 * The number of consecutive shuffle steps to be performed in each call
	 * to each sorting procedure.
	 */
	private static final int SHUFFLE_COUNT = 1;

	/**
	 * Tests shuffling methods.
	 * @param args is not used.
	 */
	public static void main(String[] args) {
		System.out.println("Results of " + SHUFFLE_COUNT +
								 " consecutive perfect shuffles:");
		int[] values1 = {0, 1, 2, 3};
		for (int j = 1; j <= SHUFFLE_COUNT; j++) {
			perfectShuffle(values1);
			System.out.print("  " + j + ":");
			for (int k = 0; k < values1.length; k++) {
				System.out.print(" " + values1[k]);
			}
			System.out.println();
		}
		System.out.println();

		System.out.println("Results of " + SHUFFLE_COUNT +
								 " consecutive efficient selection shuffles:");
		int[] values2 = {0, 1, 2, 3};
		for (int j = 1; j <= SHUFFLE_COUNT; j++) {