teaching machines

CS 145 Lecture 31 – Hello, Objects

November 28, 2016 by . Filed under cs145, fall 2016, lectures.

Dear students,

We’ve seen the Computer as a Calculator, a Chef, a Philosopher, a Pilot, and a Factory Worker. We’ll see it in two more roles: a Scribe and a Creator. A scribe is literate, recording accounts and memories for later retrieval. We’ve already seen how we can use Scanner to retrieve data from a file. We’ll take a quick peek at how we can write to a file: we’ll write a little message of the day (MOTD) application that greets us.

Then we’ll move on to our last personality: the Computer as a Creator. Up till this point, code and data have been two separate souls in our code. Now, we will marry them. We’ll organize code and the data that it operates on into a single being: an object.

Objects have state (data) and behaviors (methods). The state does not belong to just a method; it belongs to the object and lives as long as the object. The object can be made to do things through its behaviors. Sometimes these behaviors just share a view of the object’s state (getters or accessors), and sometimes these behaviors edit the object’s state (setters or mutators).

Code-wise, we still use the class construct to create an object in Java. But there are two big differences between the code we’ve been writing and the code we’re about to write:

  1. We do not qualify methods of an object with the keyword static, which we’ll talk about in more detail later.
  2. We declare the state of an object outside all methods, marking each variable as private. Technically, state does not have to be private, but doing otherwise is considered poor design. The more you open up the inner workings of an object, the harder it will be to improve and maintain the object.

The big deal about objects is their organizational power. They let us model an entity, a being from the domain of the problem we are trying to solve in language close to the problem we are trying to solve. And the first problem we’ll try to solve is one inspired by a part-time job I had in college. Derek and I had to create a website for McGraw-Hill to help college students track what they ate and analyze the results. So, let’s model an NDeckerBurger.

What’s the state of an NDeckerBurger? The number of decks or patties. We will declare a single piece of state, an instance variable, to hold the number of decks. We will make it private:

public class NDeckerBurger {
  private int ndecks;
}

Do we need other state? Perhaps we could add state for the number of pickles, bacon strips, cheese slices and so on. But really, these could just be derived properties. We can determine their number from ndecks with a little arithmetic. We will add some getters to compute their amounts. Let’s also add a method to count up the calories in a NDeckerBurger, using these numbers that I pulled from the internet some years ago:

Let’s also add some setters: a setPattyCount method and a merge method that unites two burgers.

The primary thing to get used to when writing code for an object is that not all the data needs to come from parameters. As long as a method is not static, it also has access to any instance variables in the class. Let’s write a getName method to contrast this. Previously, when code and data were separate, we would write a static helper method like this:

public static String getName(int ndecks) {
  if (ndecks == 0)
    ...
}

Now, we can assume that getName is being called on an actual NDeckerBurger object, which will provide its number of decks to this method automatically:

public String getName() {
  if (ndecks == 0)
    ...
}

Here’s your TODO to complete before we meet again:

See you next class!

Sincerely,

P.S. Here’s the code we wrote together…

Quoter.java

package lecture1128;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;
import javax.swing.JOptionPane;

public class Quoter {
  public static void main(String[] args) throws FileNotFoundException {
    String name;

    File nameFile = new File("/Users/johnch/.quoter");

    if (!nameFile.exists()) {
      name = JOptionPane.showInputDialog("Who are you?");

      // remember the name
      PrintWriter out = new PrintWriter(nameFile);
      out.println(name);
      out.close();
    } else {
      // use the existing name
      Scanner in = new Scanner(nameFile);
      name = in.nextLine();
      in.close();
    }

    ArrayList<String> quotes = new ArrayList<>();

    Scanner in = new Scanner(new File("/Users/johnch/Desktop/quotes.txt"));
    while (in.hasNextLine()) {
      quotes.add(in.nextLine());
    }
    in.close();

    Random generator = new Random();
    int i = generator.nextInt(quotes.size());
    String quote = quotes.get(i);

    JOptionPane.showMessageDialog(null, "Hi, " + name + "! Here's your inspiration for the day:\n" + quote);

  }
}

NDeckerBurger.java

package lecture1128;

public class NDeckerBurger {

  private int ndecks;
  
  public NDeckerBurger(int givenDeckCount) {
    ndecks = givenDeckCount;
  }
  
  public int getBunCount() {
    return this.ndecks + 1;
  }
  
  public int getPicklesCount() {
    return 4;
  }
  
  public int getKetchupOunces() {
    return 4 * this.ndecks;
  }
  
  public int getCheeseCount() {
    return 3 * this.ndecks;
  }
  
  public int getBaconCount() {
    return 100 * ndecks;
  }
  
  public int getPattyCount() {
//    return getBunCount() - 1;
    return ndecks;
  }
  
  public void doublify() {
    ndecks *= 2;
  }
  
  public void merge(NDeckerBurger that) {
    this.ndecks += that.getPattyCount();
  }
  
  public double getCalorieCount() {
    double calories = 211 * getPattyCount() +
                   27 * getBunCount() +
                   31 * getCheeseCount() +
                   1 * getPicklesCount() +
                   41 * getBaconCount() +
                   10 * getKetchupOunces() / 0.4;
    return calories;
  }
}

BurgerTime.java

package lecture1128;

public class BurgerTime {
  public static void main(String[] args) {
    NDeckerBurger pleaseStop = new NDeckerBurger(1);
    NDeckerBurger deathMachine = new NDeckerBurger(12);
    
    pleaseStop.doublify();
    pleaseStop.merge(deathMachine);

//    NDeckerBurger.getCalorieCount()
    System.out.println(pleaseStop.getCalorieCount());
  }
}