Swift Solutions: Composite

Eman Harout
Aug 6, 2017 · 5 min read
Composite Pattern in Swift - Tree

Swift Solutions is a series of articles covering design patterns in Swift. In each chapter we discuss what the pattern is, when it applies, and how to implement it.

The Composite Pattern brings consistent behavior to tree data structures. Though it has a niche application, it is very helpful when applicable. In this edition of Swift Solutions, you will learn what the pattern is, how to implement it, and identify when it should be applied.

Definition

The Composite Pattern involves a tree hierarchy of collections and individual objects. It allows for clients to treat each hierarchical element in the same way.

The pattern involves the usage of a tree hierarchy. Each element in the tree is either an individual or collection object. Collection objects contain an array of elements, which can be a mix of individual and collection objects.

Every object in the tree shares the same interface, therefore clients can treat them as the same type.

Illustration

The Composite Pattern involves a tree hierarchy of collections and individual objects.

In the above illustration, we have a directory of folders and mp3s. A folder simply contains an array of files. Each folder’s collection can contain a mix of mp3s and additional folders. This illustration nicely corresponds to each part of our definition:

  • Hierarchy -> Directory
  • Collection Object -> Folder
  • Individual Object -> mp3 File

It allows for clients to treat each hierarchical element in the same way.

All files in the hierarchy share a common interface, regardless of whether it is a folder or mp3. For example, both mp3s and folders are files which can be renamed, moved, and duplicated. So it is reasonable to expect conformance to a protocol that requires the implementation of file-like behaviors.

The important takeaway is that clients can treat groups and individual parts uniformly. There is no need to constantly type-check every file before using it. This is directly the result of having elements derive from the same protocol or base class.

UML

Composite Pattern in Swift - UML

Component: Abstractions that provide a common interface for collections and individual objects. All elements in the tree must be derived from a component protocol or base class.

Primitive: Previously referred to as an “individual object.” Primitives are simply components in the tree that do not contain child components.

Composite: Previously referred to as a “collection object.” Composites are objects that hold an array of components. While Composite and Primitive objects share the same interface, composites contain additional methods to manage its children.

Just a heads up: there are several ways of referring to our concrete components:

Composite Pattern in Swift - Table of Synonyms

I personally prefer the terms “composite” and “primitive.” With that out of the way, let’s jump into code!

Implementation

In our example, we will distribute a bonus payment to a company’s departments, which will eventually make its way down to the employees. In this scenario, departments and employees function as our composites and primitives respectively.

Component

protocol Payee {
var name: String { get }
var bonusAmount: Double { get }
func receive(bonus: Double)
}

First, we create a Payee protocol for our composite and primitive objects to conform to. This will be the means by which we treat them uniformly.

Employee

class Employee: Payee {
// 1
private var _name: String
private var _bonusAmount: Double = 0

var name: String { return _name }
var bonusAmount: Double { return _bonusAmount }

init(name: String) {
self._name = name
}

// 2
func receive(bonus: Double) {
_bonusAmount += bonus
}
}

Let’s look at our code in detail:

  1. We create an employee that conforms to Payee, implementing the properties name and bonusAmount.
  2. receive(bonus:) is setup as the only way to manipulate each employee’s bonus amount.

Department

Now let’s implement Department:

class Department: Payee {
private var _name: String
// 1
private var _bonusAmount: Double {
get {
var bonus = 0.0

for subunit in subunits {
bonus += subunit.bonusAmount
}
return bonus
}
set {
let splitCount = Double(subunits.count)
let splitBonus = newValue / splitCount
for subunit in subunits {
subunit.receive(bonus: splitBonus)
}
}
}
// 2
private let subunits: [Payee]

var name: String { return _name }
var bonusAmount: Double { return _bonusAmount }

init(name: String, subunits: [Payee] = []) {
self._name = name
self.subunits = subunits
}

func receive(bonus: Double) {
_bonusAmount += bonus
}
}

In detail, here is what we accomplished in creating the department class:

  1. Create a private property _bonusAmount. Its getter calculates the bonus by accessing subunits—a collection of sub-departments and employees—and returning the sum of their bonus amounts. Additionally, we include a setter that divides any assigned bonus and distributes them to each child component.
  2. Department acts as our composite by having a collection of payees.

Note that the department (and its sub-departments) don’t strictly hold any bonuses; they always distribute the bonus until it reaches an employee.

It also bears repeating that composites go beyond conforming to a shared protocol. They also implement methods for child components management. Having methods like add(Payee:) and remove(Payee:) are to be expected, but beyond the scope of this example. We simply set the child components during initialization, and prevent further modification by making subunits a private constant.

Using the Composite Pattern

// 1
let joan = Employee(name: "Joan")
let tom = Employee(name: "Tom")
let cleo = Employee(name: "Cleo")
let alex = Employee(name: "Alex")

// 2
let graphicDesignDepartment = Department(name: "Graphic Design", subunits: [cleo, alex])
let marketingDepartment = Department(name: "Marketing", subunits: [joan, tom, graphicDesignDepartment])

// 3
marketingDepartment.receive(bonus: 1000)

Here is what we did step by step:

  1. Create several employees, some of which to use in the creation of departments.
  2. Create a simple tree hierarchy: Instantiate a marketing department containing a graphic design department, with employees littered throughout.
  3. Give the marketing department a bonus of $1000. This is automatically distributed to its sub-departments and employees. Sub-departments further divide and trickle the bonus down until it reaches an employee.

Use Case

As usual, it is important to recognize when the pattern applies. Look out for the following indicators upon consideration:

  • There exists a tree hierarchy of collections and individual objects.
  • When it is desirable to treat objects in the tree uniformly, as opposed to querying each component’s type before performing an action.
  • When the composite and primitive share similar functionality.
  • Anytime a resource needs to be distributed throughout a tree hierarchy.

Conclusion

You did it! You can now deal with tree data structures efficiently.

Each design pattern is a powerful tool in your programming toolbox. It is a great achievement to always expand on the tools available to you. Congratulations, and keep on learning until next time!

Originally published at swiftcraft.io.

SwiftCraft

Master Your Craft.

Eman Harout

Written by

Love God, love others.

SwiftCraft

Master Your Craft.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade