Abstraction and Program Design
A class is designed before it is written: what one object of it keeps track of, and what other code can ask it to do. The design below is for a city bike-share system, where each docking station holds bikes for riders to unlock.
What each object knows
A station's design says that it knows how many bikes it holds and how many it has room for. It doesn't say whether the count is an
int named bikes or something else, and code that uses the station can't tell the difference. That hiding is data abstraction.Each attribute is placed by asking how many objects it belongs to. Every station holds its own number of bikes, and one station filling up leaves the others alone. So the bike count is an instance variable. The fine for keeping a bike past the time limit is one number for the whole city, and changing it changes it at every station at once. So it's a class variable.
Naming a process
A method is procedural abstraction. The code below computes the cost of a ride, at 15 cents per minute.
public static int rideCents(int minutes)
{
return minutes * 15;
}
A caller needs the name, the parameter, and what comes back. It doesn't need the body. Method decomposition builds a larger behavior from smaller ones. Each smaller behavior gets a method of its own, and one method calls another instead of repeating its work.
public static int totalCents(int minutes)
{
return 100 + rideCents(minutes);
}
The total adds a one-dollar unlock fee to the ride cost, and it gets the ride cost by calling
rideCents.Generalizing with a parameter
On free-unlock days the city drops the fee. Writing a second total method with 0 in place of 100 would duplicate code. A parameter removes the duplication:
totalCents(int minutes, int unlockFee) covers both days, and any fee the city sets later.The body of a method can also change without changing what it does. Suppose the city keeps its rates in a table, and
rideCents is rewritten to read the rate from that table instead of writing 15 into the code. The header is the same and every result is the same, so no code that calls it has to change.The program in the world
Design decisions reach past the code once a program is released.
For the bike-share system, reliability means testing the unlock code on more than the ordinary ride. It also needs a station with no bikes, one with every dock full, a ride of 0 minutes, and a ride that runs past midnight. A library someone else wrote for emailing ride receipts needs a license that allows its use. And suppose bikes can be unlocked only with a credit card. Then residents without one can't use a system their city paid for, an effect nobody planned, even though the program has no error at all.