|
CS 596 Java Programming
Fall Semester, 1998
Conceptual OO Definition
|
|
|
To Lecture Notes Index
© 1998, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 22-Oct-98
|
|
Contents of Doc 6, Conceptual OO Definition
Reference
Object-Oriented
Design Heuristics
,
Riel, Addison-Wesley, 1996
Heuristics
2.1, 2.8, 2.9, 3.3
Conceptual
Level Definition of OO
- “Extracting
the essential details about an item or group of items, while ignoring the
unessential details.”
-
- Edward
Berard
-
- What
is it?
- Can
you describe it with a simple sentence?
- It
contains data and operations (behavior) on the data
- Enclosing
all parts of an abstraction within a container
- Hiding
parts of the abstraction
- Abstractions
arranged in order of rank or level
Stack
Example
Definition
- "A
stack is a linear list for which all insertions and deletions are made at one
end of the list"
Operations
- pop,
push, isEmpty, isFull
Stack
Class
The
following Stack class is not a production level class.
class Stack {
private float[] elements;
private int topOfStack = -1;
public Stack( int stackSize ) {
elements = new float[ stackSize ];
}
public void push( float item ) {
elements[ ++topOfStack ] = item;
}
public float pop() {
return elements[ topOfStack-- ];
}
public boolean isEmpty() {
if ( topOfStack < 0 ) return true;
else return false;
}
public boolean isFull() {
if ( topOfStack >= elements.length ) return true;
else return false;
}
}
Using
the Stack
Stack me = new Stack( 20 );
me.push( 5 );
me.push( 12 );
System.out.println( me.pop() );
System.out.println( me.pop() );
A
Struct Version
struct Stack
{
float stack[100];
int topOfStack;
};
void push(Stack& it, int item)
{
it.stack[(it.topOfStack)++] = item;
}
float pop(Stack& it)
{
return it.stack[--(it.topOfStack)];
}
main()
{
Stack tryThisOut;
Stack yours, mine;
tryThisOut.topOfStack = 0;
yours.topOfStack = 0;
push( tryThisOut, 5.0 );
push( yours, 3.3 );
push( tryThisOut, 9.9 );
cout << pop( tryThisOut ) << endl;
}
Problems
with the Struct Version
Encapsulation
- Data
is encapsulated
- Operations
are not encapsulated with data
- The
boundaries of what it is become fuzzy
Information
hiding
- Data
is not hidden
- Data
is not safe!
Stack troubleAhead;
troubleAhead.topOfStack = 13;
troubleAhead.stack[ 8 ] = 29;
Some
Typical Beginner Mistakes
Struct-like
Class
One
can make a class that is just a struct dressed as a class. Avoid this doing this.
class StackData
{
public float[] elements = new float[100];
public int topOfStack = 0;
}
class Test
{
static void push(Stack it, int item)
{
it.stack[ ( it.topOfStack )++ ] = item;
}
static float pop(Stack it)
{
return it.stack[--(it.topOfStack)];
}
public void static main( String[] args)
{
Stack yours, mine;
push( yours, 3.3 );
push( mine, 9.9);
}
Some
Typical Beginner Mistakes
The Long Way Struct-like Class
This
example has all fields hidden. But the methods do not support the stack
abstraction. The logic of operating the stack is not in the stack class. This
means that the topOfStack field can be improperly set by some one outside the
class.
class StackData
{
private float[] elements = new float[100];
private int topOfStack = -1;
public int getTopOfStack()
{
return topOfStack;
}
public void setTopOfStack( int newTop )
{
topOfStack = newTop;
}
public float getElement( int elementIndex )
{
return elements[ elementIndex ];
}
public void setElement( int elementIndex, float element )
{
elements[ elementIndex ] = element;
}
}
Some
Typical Beginner Mistakes
The God Class
If
we have a lot of struct-like classes, then the logic of manipulating the data
needs to be placed somewhere. One bad solution is to combine the logic of
manipulating the data of all(most) struct-like classes in on big class. This
"god" class then knows everything about your program, hence the name. This make
the program hard to maintain because to understand the "god" class one has to
understand the entire program.
Some
Typical Beginner Mistakes
Mixing IO and an Abstraction
Adding
IO to the push and pop methods make the stack class unusable. This often
happens in student assignments.
class Stack {
private float[] elements = new float[ 100 ];
private int topOfStack = -1;
public void push( )
{
float item = Console.readFloat( "Type a float to push");
elements[ ++topOfStack ] = item;
}
public void pop()
{
Console.println( "Top stack item: " +
elements[topOfStack--];
}
}
class Test
{
public void static main( String[] args)
{
Stack yours ohNo = new Stack();
ohNo.push( );
ohNo.push( );
ohNo.pop( );
}
Design
Heuristics
- All
data should be hidden within its class
- A
class should capture one and only one key abstraction
- Keep
related data and behavior in one place
- Beware
of classes that have many accessor methods in their public interface. This
implies data and behavior are not in one place
Applying
these heuristics to your classes will go a long way to help you avoid typical
beginner mistakes in designing classes
Information
Hiding - Physical and Logical
Physical
information hiding
Physical
information hiding is when a class has a field and there are accessor methods,
getX and setX, setting and getting the value of the field. It is clear to
everyone that there is a field named X in the class. The goal is just to
prevent any direct access to X from the outside. The extreme example is a
struct converted to a class by adding accessor methods. Physical information
hiding provides little or no help in isolating the effects of changes. If the
hidden field changes type than one usually ends up changing the accessor
methods to reflect the change in type.
class PhysicalHiding
{
private int a;
private int b;
public int getA()
{
return a;
}
public int getB()
{
return b;
}
public int setA( int newA )
{
a = newA;
}
public int setB( int newB )
{
b = newB;
}
}
Logical
Information Hiding
Logical
information hiding occurs when the class represents some abstraction. This
abstraction can be manipulated independent of its underlying representation.
Details are being hidden from the out side world. Examples are integers and
stacks. We use integers all the time without knowing any detail on their
implementation. Similarly we can use the operations pop and push without
knowing how the stack is implemented. Given the following interface to a Point
class is there any way to determine how it is implemented? Does it use polar
coordinates internally or not?
class
Point
public
int getX()
public
int getY()
public
int setXY( int newX, int newY )
public
int getRadiusVector()
public
int getPolarAngle()
public
int setRadiusVector( float newRadius)
public
int setPolarAngle( float newAngle)
Example
- Linked List of Floats
What
operations do we want on a linked-list?
- addFirst(
float data )
- addLast(
float data )
- contains(
float data )
- get(
int index)
- getFirst()
- getLast()
- indexOf(
float data)
- insert(
int index, float data)
- contains(
float data )
- removeFirst()
- removeLast()
- remove(
int index)
- remove(
float data)
- removeAll(
float data )
- size()
How
to implement? In C we would use a struct
struct Node
{
float data;
struct Node* next;
};
then
use it to implement the above functions.
First
Java Linked List
package MyLinkedList;
public class LinkedList {
private Node frontOfList = null;
public void addFirst( float data )
{
Node newNode = new Node();
newNode.data = data;
newNode.next = frontOfList;
frontOfList = newNode;
}
public String toString() {
String listAsString = "";
Node current = frontOfList;
while (current != null ) {
listAsString = listAsString + " " + current.data;
current = current.next;
}
return listAsString;
}
// Other methods deleted
}
class Node {
float data;
Node next = null;
}
Using
the First Linked List
import
MyLinkedList;
public class Test
{
public static void main( String args[] ) throws Exception
{
//new ClassMethodView( Test.class );
LinkedList test = new LinkedList();
test.addFirst( 1);
test.addFirst( 2);
test.addFirst( 3);
System.out.println( test );
}
}
Output
3.0 2.0 1.0
What
is Wrong with the Node Class?
Clearly
the Node class does what an earlier slide says not to do. So what? Most
textbooks will have Node code that looks like the first example. The Java
library source code has many instances of linked lists that use this type of
Node class. So what is wrong with Node class? Put another way how can it be
improved?.
Think
about this before going on to the next slide.
Second
Node Class
class Node {
private float data;
private Node next = null;
private Node previous = null;
public Node( float initialData) {
this( initialData, null, null );
}
public Node( float initialData,
Node previousInList,
Node nextInList ) {
data = initialData;
next = nextInList;
previous = previousInList;
if ( next != null )
next.previous = this;
if ( previous != null )
previous.next = this;
}
public void append( float data ) {
new Node( data, this, next);
}
public void prepend( float data ) {
new Node( data, previous, this);
}
//
Node Continued
public void remove() {
if ( previous != null )
previous.next = next;
if ( next != null )
next.previous = previous;
}
public Node getNext() {
return next;
}
public Node getPrevious() {
return previous;
}
public float getData() {
return data;
}
public void setData( float newData ) {
data = newData;
}
}
Second
Linked List
public class LinkedList {
private Node frontOfList = null;
private Node endOfList = null;
public void addFirst( float data ) {
frontOfList = new Node( data, null, frontOfList );
if (endOfList == null )
endOfList = frontOfList;
}
public void addLast( float data ) {
endOfList = new Node( data, endOfList, null );
if (frontOfList == null )
frontOfList = endOfList;
}
public float removeFirst( ) {
Node oldFirst = frontOfList;
frontOfList = frontOfList.getNext();
oldFirst.remove();
return oldFirst.getData();
}
public String toString() {
String listAsString = "";
Node current = frontOfList;
while (current != null ) {
listAsString = listAsString + " " + current.getData();
current = current.getNext();
}
return listAsString;
}
}
Is
the Second List Better?
What
is the difference between the first and second Node classes?
Is
the second Node better? If so how?
Computation
as Simulation
Procedure
programming consists of procedures acting on data
Object-oriented
programming consists of objects interacting
Main()
creates web of objects and starts them interacting
The
OO Process
Step
One
- Identify
the data and the operations on the data
- These
start to form the classes
Step
Two
- Determine
how classes interact
Step
N
- Create
program on top of the classes
Copyright © 1998 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA.
All rights reserved.
visitors since 15-Sep-98