CPSC 210

D4: Composite Pattern

🍄 🐘 🦆 🐟 🐍 🦋 🐸 🦖🌳 🌸 🍓 🥒 🍎 🥜🌿

Learning Goals

  • Justify use of design patterns
  • Explain where design patterns come from
  • Apply the Composite Design Pattern to a given problem

We make mistakes

We identify our mistakes

We fix our mistakes

We learn to prevent them in future

We Evolve Design Patterns

Lessons Learned!

Why Design Patterns?

Maybe...
Then we iterate!

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"

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?
  • The 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", hammer);
Box techBox = new Box("Tech Box", phone, headphones);
Box chargerBox = new Box("Charger Box", charger);

Box electronicsBox = new Box("Electronics Box", techBox, chargerBox);
Box orderBox = new Box("Shipment Box", toolBox, electronicsBox, receipt);

orderBox.printContent();
orderBox.printTotalPrice();

Products and Boxes (3)

private void addButtonPanel() {
    JPanel buttonPanel = new JPanel();
    buttonPanel.setLayout(new GridLayout(4,2));
    buttonPanel.add(new JButton(new AddCodeAction()));
    buttonPanel.add(new JButton(new RemoveCodeAction()));
    buttonPanel.add(new JButton(new ArmAction()));
    buttonPanel.add(new JButton(new DisarmAction()));
    buttonPanel.add(new JButton(new AddSensorAction()));
    buttonPanel.add(new JButton(new ClearLogAction()));
    buttonPanel.add(new JButton(new PrintLogAction()));
    buttonPanel.add(createPrintCombo());
		
    controlPanel.add(buttonPanel, BorderLayout.WEST);
}

Where have I seen
something like this ?

Alarm Controller UI

Swing Containers/Components form a Component hierarchy, and Swing can paint them (and various other actions) recursively!

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

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

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)

In other words

Lecture Ticket 

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

See part 3 answer!

Lecture Lab

  1. Draw a UML Class Diagram (including all methods!) with Branch, Leaf, and Offshoot
     
  2. Implement the behaviour in startfromscratch
     
  3. Try again via refactoring in refactortogetthere

D4: Composite Pattern

The End - Thank You!

CPSC210 - D4: Composite

By Steven Wolfman

CPSC210 - D4: Composite

  • 22