Topic 9: Aggregation - Objects within Objects
So far we have considered single objects, or objects within arrays or ArrayLists. However, real
object-oriented systems typically have many objects interacting with one another. A common
scenario is to have objects within other objects and this is called aggregation.
Why is aggregation useful?
Imagine we wanted to write a program to manage stock for a shop. We could write a main() which
creates an ArrayList of Product objects (as in the example last week) and implement functionality within
the main() to search for products, sells products, adds new products and so on.
However a more object-oriented approach would be to create a class which represents the shop as a
whole. This class could be called Shop. It could contain methods to add a new
product, search for a product, or sell a product, and could contain, within it, an ArrayList
of Product objects (this would be the aggregation). The advantage of creating a Shop class
is that it could be reusable: we could create a Shop class which
represents a shop, and then reuse it in many different programs.
Example
This example shows the use of a Shop class, as well as a Product class and a test main.
Note how, as for
last week, I have removed the this. when referring to attributes.
// Product class
public class Product
{
private String name;
private double price;
private int quantityInStock;
public Product (String nameIn, double priceIn, int quantityIn)
{
name = nameIn;
price = priceIn;
quantityInStock = quantityIn;
}
public void print()
{
System.out.println("Name=" + name + " Price=" + price + " Quantity in stock=" + quantityInStock);
}
public void sell()
{
if(quantityInStock > 0)
{
quantityInStock--;
}
else
{
System.out.println("Insufficient quantity in stock");
}
}
public String getName()
{
return name;
}
}
// Shop class
import java.util.ArrayList;
public class Shop
{
private String name;
private ArrayList<Product> products;
public Shop(String nameIn)
{
name = nameIn;
products = new ArrayList<Product> ();
}
public void addProduct (Product p)
{
products.add(p);
}
// Search for a product by name
public Product searchForProduct (String searchName)
{
for(int count=0; count < products.size(); count++)
{
Product currentProduct = products.get(count);
if(currentProduct.getName().equals(searchName))
{
return currentProduct;
}
}
return null;
}
public void sellProduct (String productName)
{
Product p = this.searchForProduct (productName);
if (p != null)
{
p.sell();
p.print();
}
else
{
System.out.println("No product with that name");
}
}
}
// Test main
public class ShopTestApp
{
public static void main (String[] args)
{
Shop shop = new Shop("Cottage Stores");
shop.addProduct
(new Product ("Cheese", 1.99, 10));
shop.addProduct
(new Product("Milk", 0.50, 20));
shop.addProduct
(new Product("Bread", 1.19, 15));
shop.sellProduct("Cheese");
shop.sellProduct("Spam");
}
}
How is this working?
- We have a Shop class which contains an ArrayList of Products within it.
This is aggregation.
- The ArrayList of Products is private. This is encapsulation again.
The outside world (e.g. the main() ) cannot access the ArrayList directly. Access to the
ArrayList is controlled by the Shop. The only way the outside world can manipulate the
array list is via the methods of Shop. You can think of each method of Shop as a "portal" or
"gateway" through which the inner workings of Shop exchange information from the outside world.
Each "portal" (method) would typically include some validation, to check that the outside world isn't
doing anything unrealistic. The diagram below shows this.
- For example, searchForProduct() will return
null if the product cannot be found.
Note the use of .equals() to compare strings in searchForProduct(). When comparing strings,
we do not use ==. We instead, use the .equals() method of the String class, passing in the
string to compare to as a parameter.
- The sellProduct() method contains error checking: it will attempt to sell a given product and if it
cannot be found, it will display an error. It calls searchForProduct() to try
and find the product with that name. If it can be found, a Product object is returned, and
the product is sold by calling its sell() method. If it cannot be found,
null is returned and we display an error.
- Therefore, we have a Shop class which models how a shop works in Java
code - with inbuilt error checking. This Shop class, with its error checks, could thus be
reused in any Java program, and the error checks wouldn't have to be written again.
Exercise - Address Book
The exercise involves writing a simple address book system. There are two classes: Contact (representing a contact in the
address book) and AddressBook (representing the address book as a whole).
- Write a Contact class. It should have attributes for name, address and phone number
(all Strings), and a constructor which
initialises these three attributes to the parameters passed in.
- Write a method of Contact called updateDetails().
It should take two parameters (new address, and new phone number) and
set the address and phone number attributes appropriately. Before doing so, the parameters should be validated to check that
they are not equal to the blank string, "".
- Write an AddressBook
class. It should contain an ArrayList of Contacts. The constructor should initialise this ArrayList
appropriately.
- Write an addContact() method in AddressBook.
This should take, as a parameter, a Contact object,
and add it to the ArrayList.
- Write a search() method in AddressBook. This should take a name as a parameter and search for, and return,
the Contact with that name. null should be returned if no contact with that name exists. Assume that there will not
be two contacts with the same name!
- Write a method of AddressBook called updateContactDetails(). It should take, as parameters, the name of the
contact and the new address and new phone number. It should work by making use of the search() and
updateDetails() methods above.
- Write a test class with a main() in which you create an AddressBook, add a few Contacts to it and
test out all your methods. Include error cases
to check the errors are detected!