Skip to main content
Logo image

Section 13.1 Abstraction

An abstraction is something that captures the important idea of something while ignoring irrelevant details. Almost all of programming is about creating abstractions at various levels so we can think clearly about how our programs work without getting mired in a million distracting details.
By layering abstractions we can build up from the very primitive capabalities of the computer (basically to do arithmetic very fast) to things humans care about like playing games, browsing the web, editing videos, or anything else people use computers for.
Learning to manage abstractions is in some sense the key to becoming a good programmer.

Subsection 13.1.1 Names as abstraction

The simplest form of abstraction is to give something a name. We do this all the time outside of programming: when we talk about โ€œstudentsโ€ weโ€™re capturing the abstract idea of a whole group of people and what they have in common as members of that group, while ignoring many details that make each student a unique individual.
In programming we also name things all the time and every name is a bit of abstraction. When we declare a variable like:
int total = 0;
we are creating an abstract notion of a total that could take on different values but will always represent the total of something weโ€™re keeping track of. We can think of every variable as an abstraction over all the values that variable could possibly take on.
When we use a variable in an expression like:
total > 100
then weโ€™re build a slightly higher level abstraction of checking whether a our abstract value total is greater than a specific concrete value. This expression works for any possible value for total and could be used in an if statement to decide whether to do something or not. Of course if we had another variable, goal, that abstracted away the specific value 100, we could write an even more abstract expression:
total > goal
to capture the idea of the total we are accumulating being greater than some goal that has been set elsewhere in some way we donโ€™t have to worry about when we think about what this expression means.
So once we have the ability to name things we have the ability to create new higmer levels of abstraction. Letโ€™s look at a few of the main kinds of abstraction.

Subsection 13.1.2 Data abstraction

Data abstraction is one of the simplest kinds of abstraction. A data abstraction hides the exact details of how something is represented in the computerโ€™s memory and lets us focus instead of what we can do with it.
Javaโ€™s primitive are a form of data abstraction. While the details of exactly how int and double values are represented are actually specified (an int is alwaays 32 bits, etc.) most of the time we can ignore those details and just focus on what we can do with those valuesโ€”add them, multiply them, etc. That is a lot easier to think about than if we had to think about exactly what is happening at the level of the bits every time we multiplied two numbers.
Itโ€™s worth noting that no abstraction is perfect. For example when do arithmetic with int values, the abstraction breaks down around the limits Integer.MAX_VALUE or Integer.MIN_VALUE. In the abstract, adding one to a positive integer should always yield a larger number but if we add one to Integer.MAX_VALUE we get a negative number because of the way int values are represented! But most of the time we donโ€™t have to think about those details.
Classes provide an even more flexible form of data abstraction. When we write a class we have to specify exactly how the data is stored in instance variables but when we use a well-designed class we donโ€™t have to care or even know. For example, we can use Javaโ€™s String class or the turtle libraryโ€™s Turtle class without needing to know exactly how those classes store the information that makes up each instance.

Subsection 13.1.3 Procedural abstraction

A procedural abstraction lets us give a name to a process for computing a result or producing some side effect so we can use that process without having to think about all the details of how the computation is performed.
In Java, we create procedural abstractions by writing methods. For instance a method named doubled that takes an int argument and returns a value that is twice the argument creates an abstraction of the idea of doubling a number.
public int doubled(int n) {
  // detail hidden here. Could be n * 2 or n + n or even n << 1;
}
We can also abstract computations with side effects. For example, the forward method in the Turtle class abstracts the idea of moving the turtle forward. We donโ€™t need to know exactly how the turtle is animated to move forward to use the method.
Procedural abstractions are typically built in layers via method decomposition. When we decompose a method we break it down into smaller parts which we then implement as their own methods. Hereโ€™s a toy example:
public double hypotenuse(double a, double b) {
  return Math.sqrt(square(a) + square(b));
}

public double square(double n) {
  return n * n;
}
The hypotenuse method abstracts the computation of the length of the hypotenuse of a right triangle from the lengths of the triangleโ€™s legs using the Pythogarean theorem. But it is built on top of two other procedural abstractions: Math.sqrt which comes from Javaโ€™s Math class and square, a method we wrote to abstract the idea of squaring a double value.
While making a method to abstract n * n is maybe taking things a bit too far it demonstrates the idea. By decomposing a method into helper methods, each method is an abstraction that we can think about on its own. We can ask, does square do what itโ€™s supposed to do? Once weโ€™re sure about that we can ask, does hypotenuse correctly implement the Pythogarean theorem, if we assume that Math.sqrt and square work correctly? Whereas if we had written hypotenuse to do the squaring inline as a * a and b * b it would probably still be understandable but weโ€™d have decode those two expressions to recognize that they are doing the squaring called for my the Pythogarean theorem.
In general decomposing methods down to the point where each method can be expressed in less than a half dozen lines of code is actually a good idea with several benefits:
  • Avoiding repetition: Putting even small bits of code that are duplicated throughout a program into a method and then replacing the code with calls to the method can make the overall program shorter and easier to understand.
  • Reducing complexity: even methods that are only used once, help divide a program into smaller pieces that are each easier to understand and get correct than one big method that does a lot of things. Smaller methods are easier to debug and understand because they do less.
  • Maintainability: very little code is written and never changed. When methods are decomposed and duplicate code removed by putting it into methods it is easier to make changes. If you ever find yourself fixing a bug and having to make the same changes in a bunch of different places in your program thatโ€™s a sign that that code should probably have been put into its own method s you could make the fix in one place.

Activity 13.1.1.

As a review, letโ€™s deconstruct the song โ€œOld MacDonaldโ€ into methods with parameters to avoid repetition of code, as in Unit 1.
Complete the methods chorus() and verse(). Add method calls in main.

Subsection 13.1.4 Class abstraction

In object-oriented languages like Java we can use class abstraction as a yet higher-level kind of abstraction that combines data abstraction and procedural abstraction.
When designing a program we often start by deciding which classes are needed by thinking about the nouns we use when talking about the program. The main nouns then become classes in our program and we use data abstraction within in the class by defining the instance variables that make up the class and procedural abstraction by write the methods that define what we can do with instances of the class.
For instance, if we wrote a description of the turtle drawing library weโ€™ve used in earlier chapters it would probably contain a phrase like, โ€œmake turtles that can exist on a 2-dimensional world and can draw lines by moving around the worldโ€. The main nouns in that description are โ€œturtleโ€ and โ€œworldโ€ and indeed the classes in the system are Turtle and World.
Then we can look for verbs like โ€œmoveโ€ and โ€œdrawโ€ to identify the things we need to be able to do with these classes.

Activity 13.1.2.

Youโ€™ve been hired by your school to create a program that keeps track of โ€œstudents at your school and the courses they are takingโ€. Name two classes that you would create in your program. Name two attributes (data kept in instance variables) for each class.
The two nouns in the problem description above, Student and Course would make good class names! Then, you can think about what data you need to keep track of for students and courses and what methods you need. For example, for the Student class, you might need to keep track of the studentโ€™s name and grade level. For the Course class, you might need to keep track of the course name and the teacherโ€™s name. What other attributes did you and your classmates come up with?

Subsection 13.1.5 Class diagrams

Sometimes itโ€™s useful, when designing a complex system with lots of classes, to make diagrams of the classes that show you at a glance what instance variables and methods they have. Often these can just be sketches in your notebook or on a whiteboard but there are also more formal systems such as the Unified Modeling Language (UML) for drawing these diagrams.
For example, here is a UML class diagram for the Turtle class which includes a list of its attributes and behaviors. Class Diagrams are a way to represent the classes in a program and the data and procedural abstractions found in each class. The attributes are the instance variables and the methods are the behaviors of the class. The - in front of the attributes indicate that they are private, and the + in front of the methods indicate that they are public. Here is a tutorial on class diagrams that explains it in more detail if you are curious but class diagrams are not on the AP CSA exam. If you want to draw your own, app.diagrams.net or Creately.com are good free online drawing tools for UML class diagrams.
Turtle class diagram
Figure 13.1.1. Turtle Class Diagram
Class diagrams themselves are a knid of abstraction: they shows the main structure of a class so we can think about it without showing all the details of the code weโ€™d have to write to implement the class.

Subsection 13.1.6 Group Challenge: Game Design

Working in groups, letโ€™s explore making a computer game that is an adaptation of a board game that you know. Think about what objects are in the game. For example, here is the description for Monopoly (trademark Hasbro games):
  • โ€œBuy, sell, dream and scheme your way to riches. Players buy, sell and trade to win. Build houses and hotels on your properties and bankrupt your opponents to win it all. Chance and Community Chest cards can change everything.โ€
What classes would you need to create a computer version of this game? (Remember to look for the nouns). Take one of the classes you listed, and try to come up with two pieces of data in that class that will be the instance variables. Then, come up with two methods (look for verbs) for the class that use the data in the instance variables. Write your answers below.
If your class has time, you could explore drawing a UML class diagram for your class using an online tool like Creately.com or app.diagrams.net using this tutorial on class diagrams

Project 13.1.3.

Say you wanted to make a computer game from a board game that you are playing. Think about what objects are in the game. For example, here is the description for Monopoly (trademark Hasbro games): โ€œBuy, sell, dream and scheme your way to riches. Players buy, sell and trade to win. Build houses and hotels on your properties and bankrupt your opponents to win it all. Chance and Community Chest cards can change everything.โ€ What classes would you need to create a computer version of this game? (Remember to look for the nouns). Take one of the classes you listed, and try to come up with 2 pieces of data in that class that will be the instance variables. Then, come up with 2 methods (look for verbs) for the class that use the data in the instance variables.

Subsection 13.1.7 Summary

  • (AP 3.1.A.1) Abstraction is the process of reducing complexity by focusing on the main idea. By hiding details irrelevant to the question at hand and bringing together related and useful details, abstraction reduces complexity and allows one to focus on the idea.
  • (AP 3.1.A.2) Data abstraction provides a separation between the abstract properties of a data type and the concrete details of its representation. Data abstraction manages complexity by giving data a name without referencing the specific details of the representation. Data can take the form of a single variable or a collection of data, such as in a class or a set of data.
  • (AP 3.1.A.3) An attribute is a type of data abstraction that is defined in a class outside any method or constructor. An instance variable is an attribute whose value is unique to each instance of the class. A class variable is an attribute shared by all instances of the class.
  • (AP 3.1.A.4) Procedural abstraction provides a name for a process and allows a method to be used only knowing what it does, not how it does it. Through method decomposition, a programmer breaks down larger behaviors of the class into smaller behaviors by creating methods to represent each individual smaller behavior. A procedural abstraction may extract shared features to generalize functionality instead of duplicating code. This allows for code reuse, which helps manage complexity.
  • (AP 3.1.A.5) Using parameters allows procedures to be generalized, enabling the procedures to be reused with a range of input values or arguments.
  • (AP 3.1.A.6) Using procedural abstraction in a program allows programmers to change the internals of a method (to make it faster, more efficient, use less storage, etc.) without needing to notify method users of the change as long as the method signature and what the method does is preserved.
  • (AP 3.1.A.7) Prior to implementing a class, it is helpful to take time to design each class including its attributes and behaviors. This design can be represented using natural language or diagrams.
You have attempted of activities on this page.