CISC 3130
Data Structures
Interfaces & Implementations

Modelling Social Security Numbers

Let us introduce a class that represents social security numbers.

Specification of Behavior

class SSNum {
	…

	public int getArea() {…}
	public int getGroup() {…}
	public int getSerial() {…}

	public String toString() {…}
	…
}
Notes

Choosing the Internal Representation

We decide to represent the ssnum as a String, complete with the separating '-'s.
class SSNum {
	SSNum(String ssnum) {this.ssnum = ssnum;}

	public int getArea() {return Integer.parseInt(ssnum.substring(0, 3));}
	public int getGroup() {return Integer.parseInt(ssnum.substring(4, 6));}
	public int getSerial() {return Integer.parseInt(ssnum.substring(7));}

	public String toString() {return ssnum;}
	
	private String ssnum;
}
Notes

Coding a Demo App for our Class

class SSNumApp {
	public static void main(String [] args) {
		SSNum sSNum = new SSNum("123-45-6789");

		System.out.println(sSNum);
		System.out.println(sSNum.getArea());
		System.out.println(sSNum.getGroup());
		System.out.println(sSNum.getSerial());
	}
}

A Change of Implementation (Representation)

We decide we'd like to change our implementation (i.e., internal representation) to an int (e.g., it takes up less space than the 11-byte string).
class SSNum {
	SSNum(String ssnum) {
		this.ssnum = Integer.parseInt(ssnum.substring(0, 3)) * 1000000  + Integer.parseInt(ssnum.substring(4, 6)) * 10000 + Integer.parseInt(ssnum.substring(7));}

	public int getArea() {return ssnum / 1000000;}
	public int getGroup() {return (ssnum / 10000) % 100;}
	public int getSerial() {return ssnum % 10000;}

	public String toString() {return String.format("%03d-%02d-%04d", getArea(), getGroup(), getSerial());}
	
	private int ssnum;
}
Notes

The Demo App Remains Unchanged

Some Issues

The following may not be compelling arguments just yet, but they help set the stage for what is coming. The upshot is that in situations where there is a clear set of behavior, and potentially more than one implementation, we should strive to limit ourselves to the common behavior.

Interfaces

The following is a standard approach to coding robust and flexible software, and, in particular the sort of coding we will be doing in this course.

Java's interface construct allows us to specify a set of behavior in the form of method specifications. The interface forms a data type, i.e., a specification of a set of values and the valid operations on those values. Any class that implements the interface is said to belong to the data type of the interface, i.e., an object of the implementation class is-a object of the interface type as well, and can appear in any context interface reference variables appear.

Here is an interface for our social security number:
interface SSNum {
	int getArea();
	int getGroup();
	int getSerial();
}
Notes

Implementations of the Interface

We now restate our two implementations in terms of the interface:
class StringSSNum implements SSNum {
	StringSSNum(String ssnum) {this.ssnum = ssnum;}

	public int getArea() {return Integer.parseInt(ssnum.substring(0, 3));}
	public int getGroup() {return Integer.parseInt(ssnum.substring(4, 6));}
	public int getSerial() {return Integer.parseInt(ssnum.substring(7));}

	public String toString() {return ssnum;}
	
	private String ssnum;
}
class IntSSNum implements SSNum {
	IntSSNum(String ssnum) {this.ssnum = Integer.parseInt(ssnum.substring(0, 3)) * 1000000 + 
										Integer.parseInt(ssnum.substring(4, 6)) * 10000 + Integer.parseInt(ssnum.substring(7));}

	public int getArea() {return ssnum / 1000000;}
	public int getGroup() {return (ssnum / 10000) % 100;}
	public int getSerial() {return ssnum % 10000;}

	public String toString() {return String.format("%03d-%02d-%04d", getArea(), getGroup(), getSerial());}
	
	private int ssnum;
}

The Apps

class StringSSNumApp {
	public static void main(String [] args) {
		StringSSNum stringSSNum = new StringSSNum("123-45-6789");

		System.out.println(stringSSNum);
		System.out.println(stringSSNum.getArea());
		System.out.println(stringSSNum.getGroup());
		System.out.println(stringSSNum.getSerial());
	}
}
class IntSSNumApp {
	public static void main(String [] args) {
		IntSSNum intSSNum = new IntSSNum("123-45-6789");

		System.out.println(intSSNum);
		System.out.println(intSSNum.getArea());
		System.out.println(intSSNum.getGroup());
		System.out.println(intSSNum.getSerial());
	}
}
Notes

Programming to the Interface

An interface specifies the required/recommended behavior (set of methods) via which one interacts with any class implementing the interface.

Revisiting our Apps

As we mentioned, the apps for the two ssnum implementations are identical except for the creation of the objects and the variable names.
class SSNumApp {
	public static void demo(SSNum sSNum) {
		System.out.println(sSNum);
		System.out.println(sSNum.getArea());
		System.out.println(sSNum.getGroup());
		System.out.println(sSNum.getSerial());
	}
}
class StringSSNumApp {
        public static void main(String [] args) {
                SSNumApp.demo(new StringSSNum("123-45-6789"));
        }
}
class IntSSNumApp {
        public static void main(String [] args) {
                SSNumApp.demo(new IntSSNum("123-45-6789"));
        }
}

Abstract Data Type (ADT) vs Data Structure

An abstract data type (ADT) is a specification of a set of values, the operations on these values, and the semantics of those operations. For example, our notion of a vector was: As we mentioned at the very beginning, a data structure is a data organization, management, and storage format that is usually chosen for efficient access to data.

In other words, the ADT is the abstraction of a type, while the data structure is the implementation representation of the type.

ADT and Data Structures in Java

Java's interface construct acts as a mechanism for the specification of an ADT. Taking our Vector as an example, we could abstract our notion of a vector int the following interface:
interface Vector<E> {
	E get(int index);
	void set(int index, E value);
	void add(E value);
	int getCapacity();
	int size();
}
Notes
A vector data structure would then be a concrete class implementing the above interface.
class ArrayVector implements Vector {
	// Our Version 5 Vector class
	Vector() {…}
	E get(int index) {…}	
	void set(int index, E value) {…}	
	void add(E value) {…}
	int getCapacity() {…}return capacity;}
	int size() {…}return size;}

	public String toString() {…}

	private void checkCapacity() {…}

	E [] arr;
	int capacity, size = 0;
	static final int INITIAL_CAPACITY = 10;
}

Programming to the Interface Again — List, ArrayList, and LinkedList

The vector class/type we introduced is a restricted version of a more general vector ADT, also known as a list We will now present this interface as well as two implementations and apply the above approach of programminf to the interface in that context.

The Interface-Specific App

import java.util.List;
import java.util.ArrayList;

public class ListApp {
	static void doIt(List<Integer>  basicList, List<String> exceptionList, List<Double> listDouble, List<String> listString) {
		System.out.println("===== ListApp =====");
		basics(basicList);
		exceptions(exceptionList);
		generics(listDouble, listString);
	}

	static void basics(List<Integer> list) {
		System.out.println("=== Basic Functionality ===");
		System.out.println("--- Printing and initial stats ---");
		System.out.println(list + " (" + list.size() + ")");
		System.out.println();

		System.out.println("--- Loading it up to capacity; add ---");
		for (int i = 0; i < 10; i++) {
			list.add(i * 10);
			System.out.println(list + " (" + list.size() + ")");
		}
		System.out.println();

		System.out.println("--- Incrementing each element; get and set ---");
		for (int i = 0; i < list.size(); i++)
			list.set(i, list.get(i)+1);
		System.out.println(list);
		System.out.println();
	}

	static void exceptions(List<String> list) {
		System.out.println("=== Exceptions ===");
		try {
			System.out.println(list.get(0));
		} catch (IndexOutOfBoundsException e) {
			System.out.println("Successfully caught exception on get: " + e);
		}

		try {
			list.set(0, "");
		} catch (IndexOutOfBoundsException e) {
			System.out.println("Successfully caught exception on set: " + e);
		}
		System.out.println();
	}

	static void generics(List<Double> listDouble, List<String> listString) {
		System.out.println("--- Generics");
		System.out.println();

		System.out.println("--- A List of doubles");
		for (int i = 0; i < 10; i++)
			listDouble.add((double)i);
		System.out.println(listDouble);
		System.out.println();

		System.out.println("--- A List of Strings");
		for (int i = 0; i < 7; i++)
			listString.add("Str" + i);
		System.out.println(listString);
		for (int i = 1; i < listString.size(); i++)
			System.out.println(listString.get(i).substring(1));
		System.out.println();
	}
}
Notes

The Apps for the Implementing Classes

import java.util.List;
import java.util.ArrayList;

public class ArrayListApp {
	public static void main(String [] args) {
		ListApp.doIt(new ArrayList<Integer>(), new ArrayList<String>(), new ArrayList<Double>(), new ArrayList<String>());
	}
}
import java.util.List;
import java.util.LinkedList;

public class LinkedListApp {
	public static void main(String [] args) {
		ListApp.doIt(new LinkedList<Integer>(), new LinkedList<String>(), new LinkedList<Double>(), new LinkedList<String>());
	}
}
Notes