Algorithms and OOD (CSC 207 2014F) : EBoards

CSC207.01 2014F, Class 18: OOD Design: An API for Ushahidi


Overview

Preliminaries

Admin

Upcoming Work

Fun Things with no Extra Credit Value

Extra Credit Opportunities

Academic

Peer Support

Miscellaneous

Admin Questions

Questions on the HW

The @Override Directive

I've heard some questions about the @Overrides directive, so we'll talk a bit about it.

Extending Counters

Wednesday's lab highlighted some differences in programming style between Prof. Rebelsky and Prof. Walker. We'll talk through those differences by looking at four approaches.

Code

public class Counter
{
  int val;
  int origin;

  public Counter(int origin)
  {
    this.origin = origin;
    this.val = origin;
  } // Counter(int)

  public void increment()
  {
    ++this.val;
  } // increment

  public void get()
  {
    return this.val;
  } // get()

  public void reset()
  {
    this.val = this.origin;
  } // reset()

  public String toString()
  {
    return "[" + this.val + "]";
  } // toString
} // class Counter

Incompletely specified problem: Count twice as fast. At least four possible approaches.

public class DoubleCounterOne
  extends Counter
{

  public DoubleCounterOne(int origin)
  {
    super(origin);
  } // DoubleCounterOne

  @Override
  public void increment()
  {
    this.val += 2;
  } // increment
} // DoubleCounter

Nice and small, but requires that you can access a field of the parent class. You might not be able to access that field for one of the following reasons:

We can do something very similar without accessing fields, taking advantage of the public increment method.

public class DoubleCounterTwo
  extends Counter
{

  public DoubleCounterTwo(int origin)
  {
    super(origin);
  } // DoubleCountertTwo

  @Override
  public void increment()
  {
    super.increment();
    super.increment();
  } // increment
} // DoubleCounterTwo

But what if we want to be able to "double" an existing counter? How Sam thinks about it: If we're doubling an existing counter, when we increment, we have to tell that counter to increment twice.

public class DoubleCounterThree
  extends Counter
{
  Counter counter;

  public DoubleCounterThree(Counter counter)
  {
    this.counter = counter;
  } // DoubleCounterThree(Counter)

  @Override
  public void increment()
  {
    this.counter.increment();
    this.counter.increment();
  }

  @Override
  public void reset()
  {
    this.counter.reset();
  }

  @Override
  public void toString()
  {
    return this.counter.toString();
  }

  @Override
  public void get()
  {
    return this.counter.get();
  }
} // class DoubleCounterThree

This is a strange approach. Why inherit if we're going to replace EVERY SINGLE METHOD? Polymorphism: We can use one of these DoubleCounterThree thingys any place we wanted a counter.

How does the user see differences?

Counter c1 = new Counter(0);
Counter c2 = new DoubleCounterTwo(0);
Counter c3 = new DoubleCounterThree(c1);
Counter c33 = new DoubleCounterThree(c3);
c1.get(); // 0
c2.increment(); 
c1.get(); // 0
c2.get(); // 2
c3.increment();
c1.get(); // 2
c3.get(); // 2
c1.reset(); 
c33.increment();
c1.get();  // 4
c3.get();  // 4
c33.get(); // 4

Complexity: These objects have a "is a" relationship with Counters, they also have a "has a" relationship with Counters. Some designers say that having both relationships is a bad idea. But ... BufferedReader IS A Reader HAS A Reader. In practice, we try the joint IS-A/HAS-A relationships mostly with interfaces.

Another solution, that gets similar behavior

Sam doesn't like modifying existing classes. Sam also likes the polymorphic behavior of the DoubleCounterThree.

Modeling Ushahidi