CSE116 / CSE504 Introduction to Computer Science II Dr. Carl Alphonce

advertisement
CSE116 / CSE504
Introduction to Computer Science II
Dr. Carl Alphonce
343 Davis Hall
alphonce@buffalo.edu
Office hours:
Thursday 12:00 PM – 2:00 PM
Friday 8:30 AM – 10:30 AM
OR request appointment via e-mail
PROFESSIONALISM
Turn off and put away electronics:
cell phones
pagers
laptops
tablets
etc.
© Dr. Carl Alphonce
ROADMAP
Where we’ve been
LRStruct visitors
Stack implementations
Today
Encapsulation discussion
Queue implementations
channel 1
This visitor, when executed on an LRStruct<E>, returns true if arg is found in the
LRStruct, false otherwise. What must you write in the red box below to
complete the definition of the visitor?
public class SearchVisitor<E> implements IAlgo<Boolean,E,E> {
@Override public Boolean emptyCase(LRStruct<E> host, E arg) {
return false;
}
@Override public Boolean nonEmptyCase(LRStruct<E> host, E arg) {
return
host.getDatum().equals(arg)
||
host.getRest().execute(this,arg);
}
}
Rank
1
2
3
Responses
OR
+
&&
4
5
6
AND
==
OTHER
Keyword: ||, OR
Keyword Matches:
95
This visitor, when executed on an LRStruct<E>, returns true if arg is found in the
LRStruct, false otherwise. What must you write in the red box below to
complete the definition of the visitor?
public class SearchVisitor<E> implements IAlgo<Boolean,E,E> {
@Override public Boolean emptyCase(LRStruct<E> host, E arg) {
return false;
}
@Override public Boolean nonEmptyCase(LRStruct<E> host, E arg) {
return
host.getDatum().equals(arg)
||
host.getRest().execute(this,arg);
}
}
Rank
1
2
3
4
5
6
Responses
Other
This visitor, when executed on an LRStruct<E>, returns true if arg is found in the
LRStruct, false otherwise. What must you write in the red box below to
complete the definition of the visitor?
public class SearchVisitor<E> implements IAlgo<Boolean,E,E> {
@Override public Boolean emptyCase(LRStruct<E> host, E arg) {
return false;
}
@Override public Boolean nonEmptyCase(LRStruct<E> host, E arg) {
return
host.getDatum().equals(arg)
||
host.getRest().execute(this,arg);
}
}
Rank
1
2
3
Responses
OR
&&
1
4
5
6
? TRUE :
ANDAND
OTHER
Keyword: ||, OR
Keyword
Matches:
139
Stack<E>
A stack is a Last-In First-Out (LIFO) data structure.
It must enforce the LIFO access policy, permitting
direct access only to the top element of the stack.
The allowable operations are:
void push(E item) – adds item at the top of the
stack
E pop() – removes (and returns) the top element from
a non-empty stack
E peek() – returns (but does not remove) the top
element from a non-empty stack
We don’t want to define our stack from first principles (like
we did with the Bag). Instead, we want to define Stack in
terms of some existing class.
Stack<E>
When we set out to do this (define a new class A in terms of
an existing class B), we generally have two options:
1) define A by composition with B
public class A {
private B _b;
public A() { _b = new B(); }
}
2) define A by inheritance from B
public class A extends B { ... }
java.util.Stack<E>
java.util.Stack<E> is defined by inheritance with Vector<E>.
Vector<E> is similar in functionality to the ArrayList<E>.
Because java.util.Stack<E> extends Vector<E>, all the methods
of Vector<E> are callable on a java.util.Stack<E> object.
This means that it is a stack in name only – the class cannot
enforce the LIFO access policy that should define a stack.
This class is a well-known example of making the wrong
implementation choice.
Composition can easily be used to define a new class A which
has more restricted functionality than the composed class B.
Inheritance is used to define a class A which has additional
functionality beyond what its parent class B has.
Exercise
We split the class in half; one half defined Stack<E> by composition
with ArrayList<E>, the other half defined Stack<E> by composition
with LRStruct<E>, from these starting points:
public class Stack<E> {
private ArrayList<E> _list;
public Stack() { _list = new ArrayList<E>(); }
public void push(E item) { ... }
public E pop() { ... }
public E peek() { ... }
}
public class Stack<E> {
private LRStruct<E> _list;
public Stack() { _list = new LRStruct<E>(); }
public void push(E item) { ... }
public E pop() { ... }
public E peek() { ... }
}
public class Stack<E> {
private ArrayList<E> _list;
public Stack() { _list = new ArrayList<E>(); }
public void push(E item) { _list.add(_list.size(), item); }
public E pop() { return _list.remove(_list.size()-1); }
public E peek() { return _list.get(_list.size()-1); }
public boolean isEmpty() { return _list.isEmpty(); }
}
public class Stack<E> {
private LRStruct<E> _list;
public Stack() { _list = new LRStruct<E>(); }
public void push(E item) { _list.insertFront(item); }
public E pop() { return _list.removeFront(); }
public E peek() { return _list.getDatum(); }
public boolean isEmpty() { return _list.isEmpty(); }
return _front.execute(new EmptyVisitor<E>(), null);
}
public class EmptyVisitor<E> implements IAlgo<Boolean,E,Void> {
@Override public Boolean emptyCase(LRStruct<E> host, Void _) { return true; }
@Override public Boolean nonEmptyCase(LRStruct<E> host, Void _) { return false; }
}
Exercise - observations
Stack<E> by composition with ArrayList<E>
The top of the stack is mapped to *back* of the ArrayList. This is
more efficient than mapping it to the *front*, as doing the latter
would require copying data on each push operation, and also on each
pop operation.
If the stack is empty the pop and peek methods throw an
IndexOutOfBoundsException.
Stack<E> by composition with LRStruct<E>
The top of the stack is mapped to the *front* of the LRStruct.
If the stack is empty the pop and peek methods throw an
IllegalStateException.
Exercise - encapsulation
A client of the Stack<E> class will become dependent on the
particular implementation:
Stack<String> st = new Stack<String>();
try {
st.peek();
}
catch ( ... what kind of exception is thrown? ... )
The exception thrown is determined by the internal implementation
details. This is bad – because changes in those internal
implementation details can affect client code!
Download