CS 1: Lecture 30 – Hello Objects
Dear students,
Today we start by finishing up our exercise with the card game.
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 persist data to a file. We’ll write a program that remembers the user’s name.
First, we try to read a config file for our application that has the user’s name in it:
File config = new File("/Users/johnch/Desktop/.footbook");
Scanner in = new Scanner(config);
String name = in.nextLine();
But what if that file doesn’t exist yet? We’ll need to make it. We interactive with the user to get a name and write it out to disk using a PrintWriter
:
File config = new File("/Users/johnch/Desktop/.footbook");
String name;
try {
Scanner in = new Scanner(config);
name = in.nextLine();
} catch (IOException e) {
Scanner in = new Scanner(System.in);
System.out.print("What's your name? ");
name = in.nextLine();
PrintWriter out = new PrintWriter(config);
out.println(name);
out.close();
}
System.out.println("Welcome, " + name + "!");
Subsequent runs of the program will find the file and not need to reprompt the user.
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:
- We do not qualify methods of an object with the keyword static, which we’ll talk about in more detail later.
- 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:
- Patty: 211 calories per patty
- Bun: 27 calories per bun
- Cheese: 31 calories per slice
- Ketchup: 10 calories per 0.4 ounces
- Pickles: 1 calorie per slice
- Bacon: 41 calories per strip
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.
To see how objects can encapsulate data and behavior, let’s create a Card
class and implement a simulation of War.
Here’s your TODO to complete before we meet again:
- I had some incorrect and misleading tests in the homework 5 SpecChecker. Please Team / Pull… to get a revised version.
- I’ve posted the homework 6 specification. It will be officially assigned next week, but you are free to start early. It covers 1D and 2D arrays and file writing.
- Midterm 2 is on Monday.
- The homework amnesty period opens Saturday, November 18, and ends Saturday, November 25. During this time you may resubmit any of homeworks 1 through 5 for which you do not already have credit. For each homework you wish to resubmit, you must complete one of the following exercises on the Open Kattis website, which are listed in no particular order: To claim your credit, send me one email per regrade request with the following:
- The number of the homework you want regraded.
- A screenshot from the problem submission page on Kattis, which shows both your code and the Accepted label. Zoom out in your browser window so that all of your code is visible.
See you next class!
P.S. It’s time for a haiku!
Doctor: “It’s alive!”
Igor: “Not quite, good doctor.isAlive
‘s stillfalse
.”
P.P.S. Here’s the code we wrote together…
MonteCarlo.java
package lecture1117;
import java.util.ArrayList;
import java.util.Random;
public class MonteCarlo {
public static void main(String[] args) {
ArrayList<String> deck1 = getDeck();
ArrayList<String> deck2 = getDeck();
int sum = 0;
for (int i = 0; i < 1000; ++i) {
shuffle(deck1);
shuffle(deck2);
sum += play(deck1, deck2);
}
System.out.println(sum);
}
private static int play(ArrayList<String> deck1,
ArrayList<String> deck2) {
for (int i = 0; i < deck1.size(); ++i) {
if (deck1.get(i).equals(deck2.get(i))) {
return -5;
}
}
return 5;
}
public static void shuffle(ArrayList<String> deck) {
Random g = new Random();
for (int i = deck.size() - 1; i >= 0; --i) {
int j = g.nextInt(i + 1);
String tmp = deck.get(i);
deck.set(i, deck.get(j));
deck.set(j, tmp);
}
}
public static ArrayList<String> getDeck() {
String[] suits = {
"\u2665",
"\u2666",
"\u2660",
"\u2663"
};
String[] ranks = {
"A",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"J",
"Q",
"K"
};
ArrayList<String> deck = new ArrayList<String>();
for (String suit : suits) {
for (String rank : ranks) {
deck.add(rank + suit);
}
}
return deck;
}
}
Feetish.java
package lecture1117;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Scanner;
public class Feetish {
public static void main(String[] args) throws FileNotFoundException {
File config = new File("/Users/johnch/.feetish");
String name;
try {
Scanner in = new Scanner(config);
name = in.nextLine();
in.close();
} catch (FileNotFoundException e) {
Scanner in = new Scanner(System.in);
System.out.print("Wutz u name? ");
name = in.nextLine();
PrintWriter out = new PrintWriter(config);
out.println(name);
out.close();
}
System.out.println("Hello, " + name + "!");
}
}
NDeckerBurger.java
package lecture1117;
import java.util.Random;
public class NDeckerBurger {
private int nPatties;
public NDeckerBurger(int initialPattyCount) {
nPatties = initialPattyCount;
}
public int getPattyCount() {
return nPatties;
}
public int getBunCount() {
return nPatties + 1;
}
public int getCheeseCount() {
return 3 * nPatties;
}
public int getBaconCount() {
return 4 * nPatties;
}
public int getKetchup() {
return 16;
}
public int getPickleCount() {
Random g = new Random();
return g.nextInt(nPatties);
}
public double getCalorieCount() {
return getPattyCount() * 211 +
getBunCount() * 27 +
getCheeseCount() * 31 +
getKetchup() / 0.4 * 10 +
getPickleCount() * 1 +
getBaconCount() * 41;
}
}
Breakfast.java
package lecture1117;
public class Breakfast {
public static void main(String[] args) {
NDeckerBurger burgie = new NDeckerBurger(32);
System.out.println(burgie.getCalorieCount());
}
}