A shopping list using the flyweight pattern

First, we'll need to identify the object that will be reused over and over in our flyweight patternIngredient:

struct Ingredient: CustomDebugStringConvertible {
let name: String

var debugDescription: String {
return name
}
}

The Ingredient object is a simple wrapper around our name, but it could be more complex as our program grows.

Next, we need an object that will manage the creation of those Ingredient objects. As we're leveraging the flyweight pattern, we want to reduce the number of instances of the Ingredient object:

struct IngredientManager {

The knownIngredients dictionary will act as our object cache:

    private var knownIngredients = [String: Ingredient]()

mutating func get(withName name: String) -> Ingredient {
// Check if we have already an instance

guard
let ingredient = knownIngredients[name] else {
// Register an instance
knownIngredients[name] = Ingredient(name: name)
// Attempt to get again
return get(withName: name)
}
return ingredient
}

var count: Int {
return knownIngredients.count
}
}

The Ingredients manager will act as our central store; it will contain all the instances of Ingredients we'll possibly ever need, and we'll be able to use it in our ShoppingList, as follows:

struct ShoppingList: CustomDebugStringConvertible {
private var list = [(Ingredient, Int)]()
private var manager = IngredientManager()

mutating func add(item: String, amount: Int = 1) {
let ingredient = manager.get(withName: item)
list.append((ingredient, amount))
}

var debugDescription: String {
return "\(manager.count) Items:\n\n"
+ list.map { (ingredient, value) in
return "\(ingredient) (x\(value))"
}.joined(separator: "\n")
}
}

Now, we'll be able to use this shopping list. Let's say your program takes a list of strings as input:

let items = ["kale", "carrots", "salad", "carrots", "cucumber", "celery", "pepper", "bell peppers", "carrots", "salad"]
items.count // 10

The user added 10 items, so without the flyweight pattern we'd create 10 different instances of Ingredients. Let's add them all to the shopping list, and print the results:

var shopping = ShoppingList()
items.forEach {
shopping.add(item: $0)
}
print(list)

Here is the output:

7 Ingredients:

kale x 1
carrots x 1
salad x 1
carrots x 1
cucumber x 1
celery x 1
pepper x 1
bell peppers x 1
carrots x 1
salad x 1

As there are duplicate ingredients in the list, we successfully reused the same instances of the Ingredient objects, reducing the memory footprint by 30%.

In larger applications, the flyweight pattern can yield important improvements; even more so when the program creates a lot of temporary objects for a smaller set of values.