Objects: Extended Example
Dec 19, 2015
General idea
• Simulate (model) the following situation:– A customer walks into a grocery store, picks up a few
items, pays for them, and leaves
• Let’s write a program to do this– Limitations:
• As yet, we have no way of interacting with (talking to) the program, so it will just have to run by itself
– This makes the program kind of boring– We can include some randomness to make it slightly more
interesting• We want to keep it simple
– We’ll avoid any problems; for example, we’ll assume the customer has enough money
Choosing objects
• What objects do we need?– The obvious objects are:
• A customer
• A store
• Grocery items of various sorts
• A checkout clerk
– Should we have subclasses of grocery items (milk, eggs, etc.)?
• My conclusion: No, because these items don’t have different behaviors
• In fact, they may not have any behaviors at all!
Choosing superclasses
• Our classes are (to give them names): Customer, Store, Clerk, GroceryItem– There is no obvious reason for any of these to be a
superclass (or subclass) of any of the others– I don’t know of any built-in Java classes that provide
any features we need
• Should we make a class Person and use it as a superclass of Customer and Clerk?– At the moment, I don’t see any reason to do this– We can always do it later, if we find some data or
actions that Customer and Clerk should both have
Getting started, I
• We need to create a Customer, a Clerk, a Store, and some GroceryItems – how and where?
• Here’s “how”:– The GroceryItems should be in the Store, and initially
only the Store needs to know about them, so we will let the Store create those
– The Customer and the Clerk both need to know about the Store (but the Store kind of just sits there)
• Hence, we probably should create the Store first• This is because, when we create the Clerk and the Customer,
we want to create them with knowledge of the Store
Getting started, II
• We need to create a Customer, a Clerk, a Store, and some GroceryItems – how and where?
• Here’s “where”:– We could create a separate class to control all this, but
that’s kind of pointless– The Store is the central idea of this program, so let’s
put a main method in the Store to kick things off– That means our main class will be named Store, but I
don’t like that—there are other things we “store” on a computer
– I’ll rename this class to be GroceryStore
The main method, I• What does our main method need to do?
– Create a GroceryStore– Create a Clerk for the store– Create a Customer who knows about the store– Tell the Customer to “shop”
class GroceryStore { public static void main(String args[]) {
GroceryStore store = new GroceryStore(); Clerk clerk = new Clerk(store); Customer customer = new Customer(store); customer.shop(); // This could be better...
}// other stuff...
}
The main method, II
• According to our code so far, the customer only shops in this one store– This is adequate for our program, but it’s very
restrictive and it’s trivial to fix
• class GroceryStore { public static void main(String args[]) { GroceryStore store = new GroceryStore(); Clerk clerk = new Clerk(store); Customer customer = new Customer( ); customer.shop(store); } // other stuff...}
The Customer, I
• The Customer needs to shop– This includes selecting groceries and paying for them
class Customer { public void shop(GroceryStore store) { selectGroceries(store); // because the store
// holds the groceries checkOut(???); // who or what do we pay?
} // other stuff...
}
checkOut(???)• Obviously, the Customer should pay the Clerk
– But how does the Customer know about the Clerk?• The Customer knows about (can reference) the GroceryStore• The Clerk knows about the GroceryStore• Neither the GroceryStore nor the Customer knows about the
Clerk• We can’t get there from here!
– How do we fix this?• Should the Customer know about the Clerk?
– I don’t know any clerks personally, so why should my Customer object?
• Should the GroceryStore know about the Clerk?– This makes sense to me
• However, the Clerk still needs to know about the GroceryStore
The main method, III
class GroceryStore { public static void main(String args[]) { GroceryStore store = new GroceryStore(); Clerk clerk = new Clerk(store); store.hire(clerk); Customer customer = new Customer(); customer.shop(store); } // other stuff...}
We can do this when we hire the Clerk
The Customer, II
• The Customer knows about the GroceryStore• The GroceryStore knows about the Clerk• Hence, the Customer can ask the GroceryStore
about the Clerk
class Customer { public void shop(GroceryStore store) { selectGroceries(store); checkOut(store); // later we'll ask store for clerk } // other stuff...}
The story so far...
• class GroceryStore { GroceryStore() {...} // Constructor public static void main(String args[]) {...} public void hire(Clerk clerk) {...} public Clerk getClerk() {...}}
• class Customer { public void shop(GroceryStore store) {...} public void selectGroceries(GroceryStore store) {...} checkOut(GroceryStore store) {...} }
• We haven’t yet done much with either Clerk or GroceryItem
Hiring a clerk
• There’s just one Clerk, whom we hired like this: GroceryStore store = new GroceryStore();
Clerk clerk = new Clerk();store.hire(clerk);
• So we need to write the hire method– Also, don’t forget the store and clerk need to know about each other
class GroceryStore { Clerk myClerk; public void hire(Clerk clerk) {
myClerk = clerk; clerk.takePosition(this); // "this" = this store}
}
Being hired
class Clerk { GroceryStore myStore; public void takePosition(GroceryStore store)
{ myStore = store;}
}
• Does the Clerk really need to know about the Store?– Yes, because only the Store knows about the GroceryItems
– The Clerk will need to find out about the GroceryItems in order to check out the Customer
Getting a Clerk
• This is trivial, so let’s just do it right now:
• class Store { Clerk myClerk; ... public Clerk getClerk() { return myClerk; } ...}
Stocking the Store• Next, construct a Store containing an array of
GroceryItems (along with how many of each)
// instance variablespublic int KINDS_OF_ITEMS = 4;public GroceryItem[ ] item = new GroceryItem[KINDS_OF_ITEMS];public int[ ] itemCount = new int[KINDS_OF_ITEMS];
// constructorGroceryStore() { item[0] = new GroceryItem("milk", 2.12); item[1] = new GroceryItem("butter", 2.50); item[2] = new GroceryItem("eggs", 0.89); item[3] = new GroceryItem("bread", 1.59); for (int i = 0; i < KINDS_OF_ITEMS; i++) { itemCount[i] = 50; // the store has lots of everything }}
The Customer selects groceries
GroceryItem[ ] myShoppingBasket = new GroceryItem[20];Random random = new Random();
public void selectGroceries(GroceryStore store) { int itemsInMyBasket = 0;
for (int i = 0; i < store.KINDS_OF_ITEMS; i++) { // for each kind of item for (int j = 0; j < 3; j++) { // choose up to 3 of it if (random.nextInt(2) == 1) { myShoppingBasket[itemsInMyBasket] = store.item[i]; store.itemCount[i] = store.itemCount[i] - 1; itemsInMyBasket = itemsInMyBasket + 1; } } }}
The Customer checks out
void checkOut(GroceryStore store) { Clerk clerk = store.getClerk(); double total =
clerk.ringUp(myShoppingBasket); myMoney = myMoney - total; clerk.pay(total);
}
• I used a variable myMoney--I have to remember to add that as an instance variable of Customer
The Clerk does his (or her) job public double ringUp(GroceryItem[ ] item) {
double total = 0; int itemNumber = 0; while (item[itemNumber] != null) {
total = total + item[itemNumber].price; itemNumber = itemNumber + 1;
} return total;
} public void pay(double amount) { myStore.money = myStore.money + amount; } Remember to add a variable money to GroceryStore!
The GroceryItem
• The GroceryItem doesn’t do a lot...
class GroceryItem { public String name; public double price;
GroceryItem(String name, double price) { this.name = name; this.price = price; }}
What’s left?
• The program is complete, except for one minor detail:– When it runs, we don’t know what it does
– We never printed anything
• Easy solution:– As the Clerk rings things up, print them out
– We could also have the Customer print things out as he (or she) picks them up
A little “philosophy”
• As written, the Store doesn’t do anything--it just sits there and lets people manipulate it– This is pretty much true to life– But is it a good idea for a program?
• Suppose the Customer takes more of an item than the Store has (leaving it with a negative amount)– We could make the Customer responsible– But maybe the Clerk also manipulates the amount
(stocks the shelves)– Now the responsibility is split into two different places– Suddenly, this is twice as hard to maintain– Conclusion: the Store should be responsible for its own
state, whether or not this is like “real life”