CSC 241- Set #3


Encapsulation+Inheritance

The major advantages to Object Orientation are encapsulation and inheritance.

We have already discussed encapsulation when we discussed the class Tank. An object or an instance of class tank not only has the content of a tank held inside it, it has the methods that operate on or query the content as well. An application that creates tank objects can be assured that they will never be in a bad state by having contents that are below zero or over capacity. Through the exception facility in java, applications can pinpoint problems more rapidly.

We first talked about Inheritance when we discussed the exception handling features of Java. Recall that in Java we create exception classes such as TankOverFlowException that are subclasses of a super class called Exception. It is not hard to think of why super classes such as Exception are useful. For one thing, it provides uniformity to the way we handle abnormal cases. Any of our methods that throw an exception force the application that invokes them to catch that exception. This is something that if the application programmer forgets to deal with, he or she will be reminded with a compilation error. Since all exceptions are designed in similar fashion, we have a sense of familiarity when we look at new classes that throw them. That feeling of familiarity is part of the draw for object orientation, it prevails all over the place.

Extending Tank

displayTank is a subclass of the Tank class. As the class header indicates, displayTank extends Tank (public class displayTank extends Tank).

displayTank simply adds a new functionality to the Tank class that enable us to display the Tank at some coordinate of a canvas. You should notice that displayTank does not extend canvas; thats why it has a display method instead of a paint method that the Light class had in Assignment #1. The display method will need a Graphic object as a parameter to draw on, but, unlike the paint method it must be called explicitly. You will see later that it is called from the tankApplet's paint method.

The key point to be made here is that all fields and methods of Tank are inherited by displayTank as if we had literally copied them from Tank.

The call to super in the displayTank's constructor is for the invokation of the constructor in Tank, setting of the content_ to zero in Tank gets performed because of this call. Other than that, the constructor sets the x and y coordinates of the tank.

The display as mentioned before draws the tank on the applet's canvas.

tankApplet

snapshot of the tankApplet shows the components displayed. Four buttons on top, a tank in the middle, and a textField at the bottom. tankApplet introduces a different layout manager as well, BorderLayout enable us to place components at borders of the applet's canvas (i.e. North, South, etc.). This applet is also used to introduce the use of Panel that enable us to group components together. In this applet, the four buttons are placed in a panel and the panel is placed at the north boarder of the applet's canvas.

Of course, t, our tank, is not added in the init method like other components because it is not one. If you look at the paint method here you will notice the call to t's dislplay method; this is what I ment earlier about the need for an explicite call to the display method in order to draw the tank. The only safe place to call the display method is from the paint method of an applet or some other Canvas subclass.

The action method handles the button clicks and displays messages in the textField. Notice that t.add(amt) or t.remove(amt) calls are made as if t is just a regular tank; keep in mind that displayTank "is a" Tank.

Assignment 2-Part 1

You will develop a changableTank class which extends displayTank. changeableTank has a number of functions that we'll be using in an applet for part 2. We want to be able move a tank to new locations on our canves, switch its size, and change its orientation.

  1. switchSize lets us switch the size of a tank from large to small or small to large. A boolean field (big_) is declared changableTank that starts off as true and switches back and forth as this method is called. The side effect of calling this method is that height_ and width_ are either multiplied by four or divided by four.
  2. changePosition replaces x_ and y_ with new x and y coordinates.
  3. turn changes the orientation of the tank my 90 degrees. Depending on the value of the boolean right_, we either clockwise or counterclockwise. If in the normal upright position, we lay the tank on its side; which side depends on right_. Similarly, for other orientations. facing_, with the obvious four possible values, is the field that controls the orientation of the tank. This is the field that is set by the turn method.
  4. setDirection changes the direction of the turns by switching right_ from true to false, or false to true.
  5. display would need a new version here which based on facing_, draws the tank in one of four possible orientations.

You will also write a changeableTankApplet in this part that works similarly to tankApplet except that it tests the repositioning, size-switching, and turning options of our changeableTank class.

Stacks and Queues

These two classic data structures have simple and clean behaviors that make them a good topic for a starting point in discussing data structures. Data structures refers to the representation of data in our programs/systems. Stacks and Queues both act as a container of elements with well defined methods that enter elements into them or take elements away. A Stack allows us to implement a Last In/First Out (LIFO) behavior, which simply means new elements are always put in front of the line and that is where they come off from. Queues, on the other hand, behave in First In/First Out manner.

There are numerous application for either of these data structures. For example, you issue a print command on a multi-user system, is it not possible for other people to also issue the same command? A queue allows us to process these print requests in order. An example of where a stack is useful is in implementation of a preemption mechanism for resources. Lets consider a single cpu system with multiple processes competing for access to cpu. Often we assign priority to these requests. Suppose we have 4 priority levels, 1 through 4. Now, assume a process with the lowest priority (1) takes over the cpu and is processed for a while. Suppose that a new process comes along with priority 2, it preempts the first process by taking over the cpu, but the system can't throw away the first process, so it is put on a stack. Consider a process with priority 3 coming along and preempting the process with priority 2, guess what happens to the preempted process? It gets put on the stack too, but because of the behavior of the stack, when the priority 3 process is done, it is a "no brainer" as to who should be picked from the ones preempted. The one with the highest priority will be at the top and it is the one we take off and resume processing of since the data structure is a stack.

There are variety of implementations for stacks and queues. For a queue, we can define an array and put each element that comes in in the next available spot. When it is time to take an element off, we take the element in cell zero and move the rest back. We can implement a circular queue where we keep two indexes one to the front of the queue and one to the back. In such a implementation, we don't move everything back when an element is taken off--we just move our index over to the next cell. But, its more complicated, as the name indicates when we get to the last spot in the array we circle back to the beginning. This makes adding and removing a little more complex, but the advantage is in that you don't have to move everything back, each time that you remove an element. The last implementation is a linked list. If we don't know how much room we need to put aside for our queue, we implement it with a linked list that can grow indefinitely! Here is a stack and a queue class that hold Objects. Note that they both throw Exception objects when dealing with putting elements in when there is no room or removing elements when there is nothing to remove.


  public class Stack {
    protected int size_;
    protected int top_=-1;
    protected Object l_[];
    public Stack (int size) {
      size_ = size;
      l_=new Object[size];
    }
    public boolean empty() {
      return top_ == -1;
    }
    public boolean full(){ 
      return top_ == size_-1;
    }
    public Object pop() throws Exception {
      if (empty()) throw new Exception();
      top_--;
      return l_[top_+1];
    }
    public void push(Object val) throws Exception {
      if (full()) throw new Exception();
      l_[++top_]=val;
    }
  }

  public class Queue {
  private int size_;
  private int last_=-1;
  private Object q_[];
  public Queue (int size) {
    size_ = size;
    q_=new Object[size_];
  }
  public boolean empty() {
    return last_ == -1;
  }
  public boolean full() {
    return last_ == size_-1;
  }
  public void enqueue(Object x) throws Exception {
    if (last_ == size_ - 1) throw new Exception();
    q_[++last_]=x;
  }

  public void dequeue() throws Exception {
    if (last_ == -1) throw new Exception();
    for (int i=0;i<last_;i++) q_[i]=q_[i+1]; //shift elements back by 1 cell.
  }

  public Object peek() throws Exception {
    if (last_ == -1) throw new Exception();
    return q_[0];
  }
}