Unit 3 · 18 min

3.1 Abstraction and Program Design

Name the data, name the processes, and hide everything else.

Summary, objectives and course and exam description (CED) codes

Abstraction reduces complexity by hiding details that do not matter and keeping the useful ones together. Data abstraction gives data a name (an attribute, a variable or a whole class) and procedural abstraction gives a process a name (a method). Before you write a class, design its attributes and behaviors in natural language or a diagram.

By the end of this session you can

  • 3.1.A Represent the design of a program in natural language or with diagrams that show its classes and the data and procedural abstractions (all attributes and behaviors) in each class.

3.1.A3.1.A.13.1.A.23.1.A.33.1.A.43.1.A.53.1.A.63.1.A.7

Reviewed against the CED on

Know this already? Jump to the checkpoint.

1LearnThe notes, the traps and how to remember them

1. Abstraction: focus on the main idea

A program can have thousands of details. Abstraction reduces complexity by focusing on the main idea: it hides details that do not matter for the question at hand and brings together the details that are related and useful 3.1.A.1.

You already use abstraction every time you call a method from the Java library. You know what length and Math.sqrt do. You do not know, and do not need to know, how they do it.

String city = "Lisbon";
System.out.println(city.length());
System.out.println(Math.sqrt(49.0));

Output:

6
7.0

2. Data abstraction and attributes

Data abstraction separates the abstract properties of a data type from the concrete details of how it is represented 3.1.A.2. You give data a name, and you work with the name. A double named temperature is a single variable; you never think about the bits inside it. A class is a collection of data with one name: a Song object holds a title, an artist and a length, and you pass it around as one thing 3.1.A.2.

An attribute is a data abstraction declared in a class outside any method or constructor 3.1.A.3. There are two kinds:

Kind of attribute Declared as Belongs to
Instance variable private String title; Each object. Every Song has its own title. 3.1.A.3
Class variable private static int songCount; The class. All Song objects share one count. 3.1.A.3
public class Song
{
    // class variable: one copy shared by every Song
    private static int songCount = 0;

    // instance variables: each Song has its own copy
    private String title;
    private String artist;
    private int seconds;

    public Song(String songTitle, String songArtist, int length)
    {
        title = songTitle;
        artist = songArtist;
        seconds = length;
        songCount++;
    }

    public String getTitle()
    {
        return title;
    }

    public int getSeconds()
    {
        return seconds;
    }

    public static int getSongCount()
    {
        return songCount;
    }
}

Client code in another class:

Song a = new Song("Blue Sky", "The Waves", 215);
Song b = new Song("Night Run", "Mira K", 182);
System.out.println(a.getTitle() + " " + a.getSeconds());
System.out.println(b.getTitle() + " " + b.getSeconds());
System.out.println(Song.getSongCount());

Output:

Blue Sky 215
Night Run 182
2

Each object has its own title and seconds, but there is only one songCount, so it counts both songs. Topics 3.3, 3.4 and 3.7 go deeper into both kinds.

3. Procedural abstraction and method decomposition

Procedural abstraction gives a process a name, a method, so the method can be used by knowing what it does, not how it does it 3.1.A.4.

Through method decomposition, a programmer breaks a large behavior of a class into smaller behaviors and writes one method for each smaller behavior 3.1.A.4. A procedural abstraction can also pull out a shared feature into one method instead of writing the same code twice. This code reuse helps manage complexity 3.1.A.4.

In this class, totalCost is built from smaller methods, and both cost methods reuse one rounding method instead of repeating the rounding code.

public class RoadTrip
{
    private double kilometers;
    private double litersPer100Km;
    private double pricePerLiter;
    private double tolls;

    public RoadTrip(double km, double usage, double price, double tollCost)
    {
        kilometers = km;
        litersPer100Km = usage;
        pricePerLiter = price;
        tolls = tollCost;
    }

    public double fuelLiters()
    {
        return kilometers * litersPer100Km / 100;
    }

    public double fuelCost()
    {
        return roundToCents(fuelLiters() * pricePerLiter);
    }

    public double totalCost()
    {
        return roundToCents(fuelCost() + tolls);
    }

    // shared feature: written once, used by two methods
    private double roundToCents(double amount)
    {
        return (int) (amount * 100 + 0.5) / 100.0;
    }
}
RoadTrip trip = new RoadTrip(350, 6.5, 1.79, 12.40);
System.out.println(trip.fuelLiters());
System.out.println(trip.fuelCost());
System.out.println(trip.totalCost());

Output:

22.75
40.72
53.12

The person who calls totalCost does not need to know that it calls fuelCost, which calls fuelLiters and roundToCents. They only need to know it returns the total cost of the trip.

4. Parameters make a method general

Using parameters lets one method work for a whole range of input values, called arguments, so the same method can be reused again and again 3.1.A.5. Without a parameter you might write fiveDashes, tenDashes and threeStars. With parameters, one method does all of it.

public class TextTools
{
    public static String repeat(String piece, int times)
    {
        String result = "";
        for (int i = 0; i < times; i++)
        {
            result += piece;
        }
        return result;
    }
}
System.out.println("[" + TextTools.repeat("-", 10) + "]");
System.out.println("[" + TextTools.repeat("ab", 3) + "]");
System.out.println("[" + TextTools.repeat("*", 0) + "]");

Output:

[----------]
[ababab]
[]

5. Changing the inside without telling the users

Because callers only use the name and the job of a method, the programmer can change the internals of a method (to make it faster, more efficient or use less storage) without notifying the users of the method. This works only if the method signature and what the method does stay the same 3.1.A.6.

Version 1 adds the numbers one by one:

public class NumberHelper
{
    /** Returns 1 + 2 + ... + n. Precondition: n >= 0 */
    public static int sumUpTo(int n)
    {
        int sum = 0;
        for (int k = 1; k <= n; k++)
        {
            sum += k;
        }
        return sum;
    }
}
System.out.println(NumberHelper.sumUpTo(100));
System.out.println(NumberHelper.sumUpTo(4));

Output:

5050
10

Version 2 uses a formula. It is faster for large n, but the signature sumUpTo(int) and the result are the same:

public class NumberHelper
{
    /** Returns 1 + 2 + ... + n. Precondition: n >= 0 */
    public static int sumUpTo(int n)
    {
        return n * (n + 1) / 2;
    }
}

The client code does not change, and neither does its output:

System.out.println(NumberHelper.sumUpTo(100));
System.out.println(NumberHelper.sumUpTo(4));

Output:

5050
10

Watch out: renaming the method, changing its parameter types or making it return a double changes the signature or the behavior, so every caller would have to change.

6. Design the class before you code it

Before writing a class, take time to design it: list its attributes and its behaviors 3.1.A.7. The design can be written in natural language or drawn as a diagram 3.1.A.7.

Natural language design: “A parking garage knows how many spaces it has and how many cars are inside. A car can enter only if a space is free; the garage reports whether it got in. A car can leave. The garage can report how many spaces are free.”

Diagram design (a box with the class name, then attributes, then behaviors; - means private, + means public):

+-------------------------------+
| ParkingGarage                 |
+-------------------------------+
| - capacity : int              |
| - carsInside : int            |
+-------------------------------+
| + ParkingGarage(spaces : int) |
| + carEnters() : boolean       |
| + carLeaves() : void          |
| + freeSpaces() : int          |
+-------------------------------+

The nouns became attributes (instance variables) and the verbs became behaviors (methods). Now the code almost writes itself:

public class ParkingGarage
{
    private int capacity;
    private int carsInside;

    public ParkingGarage(int spaces)
    {
        capacity = spaces;
        carsInside = 0;
    }

    public boolean carEnters()
    {
        if (carsInside < capacity)
        {
            carsInside++;
            return true;
        }
        return false;
    }

    public void carLeaves()
    {
        if (carsInside > 0)
        {
            carsInside--;
        }
    }

    public int freeSpaces()
    {
        return capacity - carsInside;
    }
}
ParkingGarage garage = new ParkingGarage(2);
System.out.println(garage.carEnters());
System.out.println(garage.carEnters());
System.out.println(garage.carEnters());
garage.carLeaves();
System.out.println(garage.freeSpaces());

Output:

true
true
false
1

Watch out: on the AP® exam, free-response questions often describe a class in words. Underline the nouns (attributes) and the verbs (behaviors) before you write any code.

Lock it in: memory hooks

  • Two kinds of abstractionData abstraction names a thing (nouns: title, score). Procedural abstraction names an action (verbs: checkOut, addPoints).
  • Attributes vs behaviorsAttributes are what an object has. Behaviors are what an object does.
  • What callers depend onCallers see the outside of the box: the method signature and what it does. The inside of the box can change.

Common misconceptions

  • "Abstraction means leaving out information the program needs."

    Not quite. Abstraction hides details that are not relevant to the question at hand. The details still exist, inside the method or class, but the user of the method or class does not need to think about them.

  • "Every attribute is an instance variable."

    Not quite. An attribute is data declared in a class outside any method or constructor. An instance variable has its own value in each object; a class variable is one value shared by all objects of the class.

  • "If I rewrite how a method works, every program that calls it must change too."

    Not quite. Callers only depend on the method signature and what the method does. You can make the inside faster or use less storage without telling them, as long as those two things stay the same.

Exam traps

  • An attribute is declared outside every method and constructor. A variable declared inside a method is a local variable, not an attribute.
  • Changing the method signature (name, parameter types or their order) is not an internal change: callers would break.
  • A method that returns the same result faster has the same behavior. A method that returns a different result has changed what it does.

2PracticeRecall it, then check yourself

In 30 seconds

  1. Abstraction reduces complexity by hiding irrelevant details and grouping useful ones.
  2. Data abstraction names data without showing how it is stored: one variable or a whole class.
  3. An attribute is declared in the class outside any method: instance variables (one per object) and class variables (one shared).
  4. Procedural abstraction names a process; method decomposition splits a big behavior into small methods and avoids duplicated code.
  5. Parameters make a method general so it works for many argument values.
  6. Design attributes and behaviors first, in natural language or a diagram, then write the code.

Cover this list, say the points out loud, then take the checkpoint without scrolling back up.

Checkpoint · 5 questions

Checkpoint: Abstraction and Program Design

Pick an answer to mark it. Every answer is explained, and you can try any question again. Your saved score counts first tries only, and stays in this browser.

  1. 1 A student calls Math.sqrt(x) in a program. The student knows the method returns the square root of x but has never seen the code inside the method. Which of the following concepts does this situation best illustrate? 3.1.A.1, 3.1.A.4
    Show answer

    Answer: B. Procedural abstraction gives a process a name so it can be used by knowing what it does, not how it does it. Data abstraction is about naming data, not a process. Overloading means several methods with the same name and different parameters, which is not the point here, and integer division has nothing to do with the situation.

  2. 2 A Bus class must keep track of the number of passengers on each bus and the total number of Bus objects that have been created. Which of the following pairs of declarations is the most appropriate for these two attributes? 3.1.A.3
    Show answer

    Answer: D. Each bus has its own number of passengers, so passengers should be an instance variable. The total number of buses belongs to the class and must be shared by all objects, so busCount should be a static class variable. Making passengers static would give every bus the same passenger count, and making busCount an instance variable would give each bus its own separate count that could not track the total.

  3. 3 A class contains the method public int countVowels(String word), which is used by many other classes. The author wants to change the method. Which of the following changes would require the users of the method to be notified? 3.1.A.6
    Show answer

    Answer: B. Users can be left alone as long as the method signature and what the method does stay the same. Changing the return type changes what callers receive, so code such as int n = obj.countVowels(w); would no longer compile. Swapping the loop type, making it faster or renaming a local variable are internal changes that callers never see.

  4. 4 Consider the following class. The code segment below the class appears in a method in another class. What is printed as a result of executing the code segment? 3.1.A.5
    public class Shipping
    {
        public static double cost(double kg, double ratePerKg)
        {
            return 5.0 + kg * ratePerKg;
        }
    }
    
    System.out.println(Shipping.cost(2.0, 3.5) + " " + Shipping.cost(4.0, 1.25));
    Show answer

    Answer: B. The same method is reused with different arguments: 5.0 + 2.0 * 3.5 is 12.0, and 5.0 + 4.0 * 1.25 is 10.0. The option 24.5 11.25 adds before multiplying, which ignores operator precedence. The option 12.0 12.0 assumes the second call reuses the first values, but each call gets its own parameter values.

  5. 5 A design for a Recipe class says: "A recipe has a name, a number of servings and a cooking time in minutes. A recipe can be scaled to a new number of servings and can report whether it is quick (under 20 minutes)." Which of the following lists only behaviors of the class? 3.1.A.4, 3.1.A.7
    Show answer

    Answer: A. Behaviors are what an object does, so they become methods: scaling the servings and reporting whether the recipe is quick. The name, the number of servings and the cooking time are attributes, the data the object has, so they become instance variables. The other two options mix one attribute with one behavior.

3PrevailLock it in for exam day

By the numbers

Name each list from memory, then reveal it to check. Each list shows how many items to recall.

  • Kinds of attribute two kinds CED 3.1.A.3
    1. instance variableits value is unique to each instance
    2. class variableshared by all instances of the class
  • Internal changes you can make without notifying method users (if the signature and behavior stay the same) three examples CED 3.1.A.6
    1. make it faster
    2. make it more efficient
    3. make it use less storage
  • Ways to represent a class design before coding two ways CED 3.1.A.7
    1. natural language
    2. diagrams

Key terms: flip the cards

Read the term, say the definition out loud, then flip to check. Struggling a little to remember is what makes it stick.

  • Abstractiontap to flip

    Reducing complexity by focusing on the main idea: hiding details that do not matter for the question at hand and grouping the useful ones.

    Example and CED codes
  • Data abstractiontap to flip

    Separating the abstract properties of a data type from the concrete details of how it is represented, by giving data a name.

    Example and CED codes
  • Procedural abstractiontap to flip

    Giving a process a name (a method) so it can be used by knowing what it does, not how it does it.

    Example and CED codes
  • Method decompositiontap to flip

    Breaking a large behavior of a class into smaller behaviors, with one method for each smaller behavior.

    Example and CED codes
  • Program designtap to flip

    Planning a program's classes, with each class's attributes and behaviors, in natural language or a diagram before writing code.

    Example and CED codes
  • Instance variabletap to flip

    An attribute declared in a class outside any method or constructor, whose value is unique to each object of the class.

    Example and CED codes
  • Class variabletap to flip

    An attribute declared with the keyword static that belongs to the class, so all objects of the class share a single copy.

    Example and CED codes
  • Classtap to flip

    The formal implementation, or blueprint, of the attributes and behaviors of an object. A class defines a reference type.

    Example and CED codes
  • Methodtap to flip

    A named block of code that only runs when it is called.

    Example and CED codes
  • Parametertap to flip

    A variable declared in the header of a method or constructor. It receives the value passed in and can be used in the body.

    Example and CED codes
  • Argumenttap to flip

    A value passed into a method or constructor when it is called.

    Example and CED codes

Questions students ask

What is the difference between data abstraction and procedural abstraction?

Data abstraction gives data a name without showing how it is stored, such as an instance variable or a whole class. Procedural abstraction gives a process a name, a method, so you can use it knowing what it does but not how it does it.

What is method decomposition in Java?

Method decomposition means breaking a large behavior of a class into smaller behaviors, with one method for each smaller behavior. The large method then calls the small ones.

Do I need to draw class diagrams on the AP® exam?

You need to be able to describe a class design: its attributes with their types and its behaviors as method headers. A simple box diagram or a clear sentence list both work as a plan.

Why do parameters make a method reusable?

A parameter lets the caller send different values each time. One general method then replaces several almost identical methods that differ only in one number or string.

Was this page helpful?

No names are ever shown, and every public comment is checked by us first. Please do not include personal details. To get a reply, email [email protected].

↑ Top

Enlarged view of the selected figure