An example using builder pattern in Swift

The “builder” pattern is a creational design pattern that is used to construct complex objects step by step. It allows you to create objects with varying configurations without the need to have multiple constructors with different parameter combinations.

Imagine we’re building a pizza ordering app where users can customize their pizzas with various toppings, size, and crust.

struct Pizza {
    let size: Size
    let crust: Crust
    let toppings: [Topping]
}

extension Pizza {
    enum Size: String {
        case small, medium, large
    }
    
    enum Crust: String {
        case thin, regular, stuffed
    }
    
    struct Topping {
        let name: String
    }
}

extension Pizza {
    class Builder {
        private var size: Size?
        private var crust: Crust?
        private var toppings: [Topping] = []
        
        func setSize(size: Size) -> Builder {
            self.size = size
            return self
        }
        
        func setCrust(crust: Crust) -> Builder {
            self.crust = crust
            return self
        }
        
        func addTopping(_ topping: Topping) -> Builder {
            toppings.append(topping)
            return self
        }
        
        func build() -> Pizza {
            guard let size = size, let crust = crust else {
                fatalError("Pizza size and crust are required!")
            }
            return Pizza(size: size, crust: crust, toppings: toppings)
        }
    }
}

extension Pizza: CustomStringConvertible {
    var description: String {
        "Pizza: \(size) \(crust) with \(toppings.map { $0.name }.joined(separator: ", "))"
    }
}

let pizza = Pizza.Builder()
    .setSize(size: .medium)
    .setCrust(crust: .thin)
    .addTopping(.init(name: "Pepperoni"))
    .addTopping(.init(name: "Mushrooms"))
    .build()

print(pizza)
// Pizza: medium thin with Pepperoni, Mushrooms

Firstly, we define define the Pizza struct with its properties: size, crust type, and an array of toppings. We also define enums for Pizza.Size and Pizza.Crust and a simple Pizza.Topping struct.

Secondly, we create a Pizza.Builder class provides methods for setting the size, crust, and adding toppings to the pizza. Each method returns the builder itself allowing for method chaining for a fluent building experience. The build() method ensures that size and crust are set and returns the final Pizza object.

Finally, we use the Pizza.Builder with method chaining to create a custom pizza with desired size, crust, and toppings.