Abstraction and Implementation

last updated 2/5/07

Abstraction Revisited

Abstraction: A model of a system that includes only the details essential to the perspective of the viewer of the system

Information hiding: The practice of hiding details within a module with the goal of controlling access to the details from the rest of the system "give the user what he needs to use the module; give the implementor only what she needs to implement the module"

Data abstraction: The separation of a data type’s logical properties from its implementation

Abstract data type (ADT): A data type whose properties (domain and operations) are specified independently of any particular implementation

Preconditions and Postconditions

Preconditions: Assumptions that must be true on entry into a method for it to work correctly

Postconditions (or Effects): The results expected at the exit of a method, assuming that the preconditions are true

We specify pre- and postconditions for a method in a comment at the beginning of the method


Abstract Methods/Abstract Classes versus Interfaces

Java Abstract Class

  • Defines a class that must be a inherited to be used.
  • Can be inherited by more than one class
  • Contains at least one abstract method

Abstract Method

  • Only includes a description of its parameters
  • No method bodies or implementations are allowed. In other words, only the interface of the method is included.

Java Interfaces

Similar to a Java class

  • can include variable declarations
  • can include methods

However

  • constants only, no variables
  • all methods must be abstract.

 

A Java interface or abstract class cannot be instantiated. However, a reference variable of the interface or abstract class may be created to point to the concrete class and/or interface implementor.

We can use an interface to formally specify the logical level of an ADT:


Example Interface

For example, see the FigureGeometry interface and the Circle class that implements it below

public interface FigureGeometry
{
  final float PI = 3.14f;

  float perimeter();
  // Post: Returns perimeter of this figure.
   
  float area();
  // Post: Returns area of this figure.
      
  void setScale(int scale);
  // Post: Scale of this figure is set to "scale".
      
  float weight();
  // Precondition: Scale of this figure has been set.
  //
  // Post: Returns weight of this figure. Weight = area X scale.
}


Example Implementor

public class Circle implements FigureGeometry
{
  protected float radius;
  protected int scale;
      
  public Circle(float radius)
  {
    this.radius = radius;
  }    
       
  public float perimeter()
  // Returns perimeter of 
  // this figure.
  {
    return(2 * PI * radius);
  }
   
  public float area()
  // Returns area of this figure.
  {
    return(PI * radius * radius);
  }
public void setScale(int scale)
  // Scale of this figure 
  // is set to "scale".
  {
    this.scale = scale;
  }
            
  public float weight()
  // Precondition: Scale of this figure 
  // has been set.
  //
  // Returns weight of this figure.
  // Weight = area X scale.
  {
    return(this.area() * scale);
  }
}


Benefits of using an interface

We can formally check the syntax of our specification. When we compile the interface, the compiler uncovers any syntactical errors in the method interface definitions.

We can formally verify that the interface “contract” is met by the implementation. When we compile the implementation, the compiler ensures that the method names, parameters, and return types match what was defined in the interface.

We can provide a consistent interface to applications from among alternate implementations of the ADT.

 

 


Example Interface: the StringLog ADT Specification

The primary responsibility of the StringLog ADT is to remember all the strings that have been inserted into it and, when presented with any given string, indicate whether or not an identical string has already been inserted.

StringLog Methods

Constructors

Transformers

Observers


The StringLogInterface

//---------------------------------------------------------------------
// StringLogInterface.java     by Dale/Joyce/Weems            Chapter 2
//
// Interface for a class that implements a log of Strings.
// A log "remembers" the elements placed into it.
//
// A log must have a "name".
//---------------------------------------------------------------------

public interface StringLogInterface
{
  void insert(String element);
  // Precondition:   This StringLog is not full.
  // 
  // Places element into this StringLog.

  boolean isFull();
  // Returns true if this StringLog is full, otherwise returns false.
  
  int size();
  // Returns the number of Strings in this StringLog.

  boolean contains(String element);
  // Returns true if element is in this StringLog, 
  // otherwise returns false.
  // Ignores case differences when doing string comparison.
  
  void clear();
  // Makes this StringLog empty.

  String getName();
  // Returns the name of this StringLog.

  String toString();
  // Returns a nicely formatted string representing this StringLog.
} 


Application Example

//----------------------------------------------------------------------
// UseStringLog.java        by Dale/Joyce/Weems                Chapter 2
//
// Simple example of the use of a StringLog.
//----------------------------------------------------------------------
public class UseStringLog
{
  public static void main(String[] args)
  { 
    StringLogInterface log;  //declare with interface
    log = new ArrayStringLog("Example Use");  //instantiate with implementation
    log.insert("Elvis");
    log.insert("King Louis XII");
    log.insert("Captain Kirk");
    System.out.println(log);
    System.out.println("The size of the log is " + log.size());
    System.out.println("Elvis is in the log: " + log.contains("Elvis"));
    System.out.println("Santa is in the log: " + log.contains("Santa"));
  }
}
/*********************** output
Log: Example Use
1. Elvis
2. King Louis XII
3. Captain Kirk
The size of the log is 3
Elvis is in the log: true
Santa is in the log: false
*/


Array Implementation


public class ArrayStringLog implements StringLogInterface 
{
  protected String name;              // name of this log
  protected String[] log;             // array that holds log strings
  protected int lastIndex = -1;       // index of last string in array 

public ArrayStringLog(String name, int maxSize)
// Precondition:   maxSize > 0
// Instantiates and returns a reference to an empty StringLog object 
// with name "name" and room for maxSize strings.
{
  log = new String[maxSize];
  this.name = name;
}public ArrayStringLog(String name) 
// Instantiates and returns a reference to an empty StringLog object 
// with name "name" and room for 100 strings.
{
  log = new String[100];
  this.name = name;
}
public void insert(String element)
// Precondition:   This StringLog is not full.
// Places element into this StringLog.
{      
  lastIndex++;
  log[lastIndex] = element;
} 
public void clear()
// Makes this StringLog empty.
{   //ensuring every element is set to null is good
  for (int i = 0; i <= lastIndex; i++)
     log[i] = null;  
  lastIndex = -1;  //could get away with just this line!
}
public boolean isFull()
// Returns true if this StringLog is full, otherwise returns false.
{              
   return lastIndex == (log.length - 1); 
}
public int size()
// Returns the number of Strings in this StringLog.
{
  return (lastIndex + 1);
}
public String getName()
// Returns the name of this StringLog.
{
  return name;
}
public String toString()
// Returns a nicely formatted string representing this StringLog.
{
  String logString = "Log: " + name + "\n\n";
  for (int i = 0; i <= lastIndex; i++)
    logString = logString + (i+1) + ". " + log[i] + "\n";
  return logString;
}
public boolean contains(String element)
// Returns true if element is in this StringLog
// otherwise returns false.
// Ignores case differences when doing string comparison.
{                 
  int location = 0;
  boolean found = false;

  while (location <= lastIndex && !found) 
  {
    if (element.equalsIgnoreCase(log[location]))  // if they match
      found = true;
    else
    {
      location++;
    }
  }
  return found;
}