In this very short lesson, we'll take an initial look at what composition looks like in Java code. In Lesson 17, we discussed how composition can be used to model a has-a relationship between objects. In this lesson, we will look at a simple example of composition.
Later in this part of the course, we'll explore the power of composition after we learn about the List and Maps data structures in Lessons 21 and 22. We'll use these data structures and composition to create components later in this course.
One of the main characteristics of an object-oriented language is that objects can be made up of other objects. This is done through composition. From a coding standpoint, this means that one or more of the fields in an object are other objects rather than primitive types or strings.
To illustrate this point, look at two examples of modeling a book in Java. In each model, we want to keep track of the following:
Let's start with an example that does not use composition, which we'll call BadBook
. In the BadBook
class, we will model all the information about the book using strings. It might look something like Listing 19.1; however, note that the getters and setters for the fields are not shown in order to make the example easier to read.
The BadBook Class
public class BadBook {
private String title;
private String isbn;
private String authorName;
private String authorStreet;
private String authorCity;
private String authorState;
private String authorZip;
private String publisherName;
private String publisherStreet;
private String publisherCity;
private String publisherState;
private String publisherZip;
private String publisherPhone;
}
This class keeps track of the minimum data required, but it feels messy. All the information is in separate fields, and there is nothing to tie the author or publisher information together.
Should a book really have a field called publisherCity
? Shouldn't a publisher be a separate entity? The same is true about the author. An authorCity
field feels sloppy. What if a book has more than one author? How do we handle that?
Let's see how we can approach this problem using composition. First, let's look at the entities we have to keep track of:
The first three are probably obvious to you, but the fourth one might not be. We're choosing to model an address as an entity because both authors and publishers have an address, and, in this example, all addresses have the same format.
Let's model these objects and then see how they relate to each other. We'll start with Address
, as shown in Listing 19.2. We will keep things simple with our Address
class by having just a street, city, state, and zip.
An Address Class
public class Address {
private String street;
private String city;
private String state;
private String zip;
}
Next, the Author
class can be created as shown in Listing 19.3. Again, we'll keep things simple by having just a first name, last name, and address.
An Author Class
public class Author {
private String firstName;
private String lastName;
private Address address;
}
Now we are using composition. The Author
class has-an address. We put the street, city, state, and zip information in the Address
object and create a field in the Author
class of type Address
to hold that information for us. This is nice because it puts all the address information in a single container.
The Publisher
class in Listing 19.4 looks similar to the Author
class, except that publishers have fields for name and phone instead of fields for first and last name.
A Publisher Class
public class Publisher {
private String name;
private Address address;
private String phone;
}
Here, again, we are using composition. We can see that the Publisher
class has-an address.
Finally, let's look at the Book
class. Things get more interesting here. We need to keep track of the title, ISBN, publisher, and all authors. To account for the possibility of having more than one author, we will create a field that is an array of Author
objects. Listing 19.5 shows what our Book
class looks like.
The Book Class
public class Book {
private String title;
private String isbn;
private Author[] authors;
private Publisher publisher;
}
We're now using composition on two levels: the Book
class has-a publisher and has-an array of authors, and the Publisher
and Author
classes each have-an address. Further, we are using an array to hold the Author
objects for our book.
This is a much cleaner design. Each set of related information—address, publisher, author, and book—is in its own class. We are using composition to build objects that contain other objects.
Composition is a powerful tool that you will use frequently in the rest of this course and throughout your career. We looked at a simple example of composition, but this is just the beginning and only introduced the general syntax of using composition. As the course goes on, we will show you how to use composition to create well-designed applications.
The following are some additional exercises to help you practice what you are learning about composition. These are to do on your own. The exercises include the following:
Exercise 1: Classroom Composition
Exercise 2: Cookbook
Put composition into practice. Take the Classroom class in Exercise Listing 19.1 and break it down into classes. Consider what things a classroom has versus what things describe a classroom. For example, a classroom has a teacher.
The Classroom Class
public class Classroom {
private String className;
private int classGradeLevel;
private String teacherFirstname;
private String teacherLastname;
private String student1Firstname;
private String student1Lastname;
private int student1Grade;
private String student2Firstname;
private String student2Lastname;
private int student2Grade;
private String student3Firstname;
private String student3Lastname;
private int student3Grade;
private int maximumNumberStudents;
}
A cookbook is often full of recipes. Exercise Listing 19.2 is a class to hold a cookbook. Use composition to simplify the Cookbook
class.
As a note, this is a pretty bad cookbook, but you can make it better. Most cookbooks have more than two recipes, and most recipes have more than three ingredients. As you refactor this listing so that it uses composition, your result should allow it to use as many recipes and ingredients as needed by the users of your new classes.
The Cookbook Class
public class Cookbook {
String title;
String authorFirstname;
String authorLastname;
Double price;
int yearPublished;
String recipe1Name;
String recipe1AuthorFirstname;
String recipe1AuthorLastname;
String recipe1Ingredient1;
Double recipe1Ingredient1Amount; // ie. 1.25
String recipe1Ingredient1MeasurementType; // ie. Tablespoon
String recipe1Ingredient2;
Double recipe1Ingredient2Amount;
String recipe1Ingredient2MeasurementType;
String recipe1Ingredient3;
Double recipe1Ingredient3Amount;
String recipe1Ingredient3MeasurementType;
String recipe1MixingInstructions;
String recipe1CaloriesPerServing;
String recipe1Servings;
String recipe2Name;
String recipe2AuthorFirstname;
String recipe2AuthorLastname;
String recipe2Ingredient1;
Double recipe2Ingredient1Amount; // ie. 1.25
String recipe2Ingredient1MeasurementType; // ie. Tablespoon
String recipe2Ingredient2;
Double recipe2Ingredient2Amount;
String recipe2Ingredient2MeasurementType;
String recipe2Ingredient3;
Double recipe2Ingredient3Amount;
String recipe2Ingredient3MeasurementType;
String recipe2MixingInstructions;
String recipe2CaloriesPerServing;
String recipe2Servings;
}
18.188.152.162