CPSC 210

D4: Composite Pattern

Slides designed by Felix Grund, based on Paul Carter’s slides

Learning Goals

  • Understand why we want to use design patterns and where they come from
     
  • To apply the Composite Design Pattern to a given problem

We make mistakes

We identify our mistakes

We learn from our mistakes

We prevent mistakes

We Evolve Design Patterns

Lessons Learned!

Why Design Patterns?

What is a design pattern?

"General, reusable solution to a commonly occurring problem within a given context in software design"

"Guidelines for software design that help you avoid mistakes that others repeatedly made in the past"

Other
definition:

What is a design pattern?

  • a re-usable approach to solving a design problem

What is NOT design pattern?

  • a re-usable library (e.g. Swing) or a reusable piece of code (e.g. ArrayList or HashSet)

What's the challenge?

  • to adopt or adapt a design pattern for one's use case
  • to decide whether a design pattern makes sense for a use case

The Composite Pattern

Products and Boxes

  • Two types of objects: Products and Boxes
  • Boxes can contain a product or other boxes
  • How to determine the price of an order?
  • Unwrap all the boxes
  • Recursively go over all the products
  • Calculate the total
  • This is not simple in a program!
  • What are the classes of products?
  • What is the nesting level?
  • A naive approach will either be painful or even impossible!
  • Work with Products and Boxes through a common interface
  • Interface declares a method for calculating the total price

Products and Boxes (2)

Product receipt = new Product("Receipt", 0.0);
Product hammer = new Product("Hammer", 20.00);
Product phone = new Product("Phone", 500.00);
Product headphones = new Product("Headphones", 50.00);
Product charger = new Product("Charger", 35.00);

Box toolBox = new Box("Tool Box");
toolBox.addItem(hammer);

Box techBox = new Box("Tech Box");
techBox.addItem(phone);
techBox.addItem(headphones);

Box chargerBox = new Box("Charger Box");
chargerBox.addItem(charger);

Box electronicsBox = new Box("Electronics Box");
electronicsBox.addItem(techBox);
electronicsBox.addItem(chargerBox);

Box orderBox = new Box("Order Box");
orderBox.addItem(toolBox);
orderBox.addItem(electronicsBox);
orderBox.addItem(receipt);

double price = orderBox.getPrice();
System.out.println("TOTAL PRICE: " + price);

Products & Boxes - Main Method

public abstract class Item {

  protected String name;

  public Item(String name) {
    this.name = name;
  }

  abstract double getPrice();

}

Composite Implementation

Component

public class Box extends Item {
  private List<Item> items;

  public Box(String name) {
    super(name);
    this.items = new ArrayList<>();
  }

  public void addItem(Item item) {
    this.items.add(item);
  }

  public double getPrice() {
    double sum = 0;
    for (Item item : items) {
      sum += item.getPrice();
    }
    return sum;
  }
}

Composite

public class Product extends Item {
  private double price;

  public Product(String name, double price) {
    super(name);
    this.price = price;
  }

  public double getPrice() {
    return price;
  }
}

Leaf

Composite: Motivation

I have a tree structure and I don't know all the types of objects in the tree.

I want to run some operations recursively through my tree without knowing the exact types in my tree.

Composite Pattern

Composite node: arbitrarily many children

Leaf node:
no children

When should I (not) use it?

  • You want to implement a tree-like structure
  • You have common functionality for all components in a tree
  • Sometimes it's hard to find a common interface for components 
  • Components might sometimes not be "common enough" (overgeneralizing)

How to use it?

  • Identify your tree structure
    • composite objects and leaf objects
    • if you don't have such a structure, this pattern makes no sense!
  • Introduce abstract type that captures common behaviours of both:
    • Composite objects
    • Leaf objects

Composite Class Diagram

In other words

Lecture Ticket

  • You have branches and leaves.
  • Branches can have offshoots of either branches or leaves.
  • Leaves, obviously, cannot have any offshoots.
  • You choose to model this in Object Orientation using the Composite Pattern.
  • You identify three classes: Branch, Leaf and the third class, Offshoot.

Lecture Ticket - Part 1

What hierarchical relationship do these classes have to one another?

  • Leaf extends Offshoot
  • Branch extends Offshoot
  • Offshoot extends nothing

We identify Offshoot as the component, Branch as the composite, and Leaf as the the leaf

Lecture Ticket - Part 2

Which of the following fields would exist in Offshoot, Branch and Leaf?

  • Branch has a list of Offshoot

The aggregation from Branch to Offshoot would be implemented by adding a field of type List<Offshoot> to the Branch class.

Lecture Ticket - Part 3

Imagine that you want to change the color of all the leaves to red. You want to do this by adding a changeColor(Color) method. Where might the method be specified but not implemented?

The changeColor(Color) method is one that we would want to call on both a Leaf (to change the color of that individual leaf) and on a Branch (to change the color of all the leaves attached to that branch). This is therefore common behaviour that we want all offshoots (whether they be a branch or a leaf) to support. The method is therefore specified in the Offshoot class.

Lecture Ticket - Part 4

Where would the changeColor method be implemented?

  • In Branch, where it has a for-loop that iterates over its entire internal collection recursively invoking changeColor(Color) on each element
  • In Leaf, where it changes the field that holds the color

Lecture Lab

Lecture Lab Class Diagram

Let's make it prettier

tree changing color to RED
--b3 changing color to RED
----b2 changing color to RED
------l3 changing color to RED
----l4 changing color to RED
--b1 changing color to RED
----l1 changing color to RED
----l2 changing color to RED

Let's add indentation:

CPSC 210

D4: Composite Pattern

Composite Class Diagram

Lecture Lab #2

Lecture Lab #2

Lecture Lab Class Diagram

Folder

File

FileSystemResource

addChild(...)

print()

Lecture Lab Class Diagram

Folder

File

FileSystemResource

addChild(...)

print()

D4: Composite Pattern

The End - Thank You!

D4: Composite

By firas_moosvi

D4: Composite

  • 102