Turbocharge Your Swift Code with These 7 Powerful Structural Design Patterns

Experienced iOS and React Native Developer with 10+ Years of Expertise - Available for New Opportunities. Connect Now!
Search for a command to run...

Experienced iOS and React Native Developer with 10+ Years of Expertise - Available for New Opportunities. Connect Now!
Unlock the power of Design Patterns in Swift! Explore Creational, Structural & Behavioral Patterns for robust, maintainable & scalable iOS apps. Learn through detailed examples.
To check the previous article in this Design Patterns in Swift please visit Structural Design Patterns. Behavioral Design Patterns are key to enhancing your Swift application's responsiveness and communication between objects. This blog post will del...
This time, I'm exploring the fascinating world of AI, stepping away from my usual focus on iOS development. There's so much more to share about AI, and I can't wait to dive into it with you! If you'd like to follow along and receive regular updates, ...

The app is Time Tango, a Pomodoro timer app. I chose this concept after conducting keyword research for popular terms that face minimal competition on the app store. The app is free to use and received approval in its first review. The strategy focus...

In my last article, I talked about how data flows in SwiftUI. Now, Apple has released something new in iOS 17 - the Observation Framework. This changes how SwiftUI works with data. In this article, we will look at how to use the new Observable Macro ...

One of the critical elements of SwiftUI is its approach to managing data flow within applications. This comprehensive guide will provide you with a strong understanding of data flow in SwiftUI, how it operates, and why it's vital for your SwiftUI app...

Arrays are one of the most common data structures used in programming. In Swift, arrays are used to store ordered lists of values of the same type. They are incredibly versatile and powerful, but using them efficiently is key to writing high-performi...

To check the previous article in this Design Patterns in Swift please visit Creational Design Patterns.
Structural Design Patterns play a crucial role in organizing your code and creating flexible, efficient, and scalable systems. In this blog post, we'll explore 7 game-changing Structural Design Patterns for Swift developers, complete with detailed code examples that you can implement in your projects right away. Get ready to turbocharge your Swift code!
The Adapter pattern allows two incompatible interfaces to work together by wrapping one with an adapter that matches the other's expectations.
protocol Target {
func request()
}
class Adaptee {
func specificRequest() {
print("Specific request")
}
}
class Adapter: Target {
private let adaptee: Adaptee
init(adaptee: Adaptee) {
self.adaptee = adaptee
}
func request() {
adaptee.specificRequest()
}
}
// Usage
let adaptee = Adaptee()
let adapter: Target = Adapter(adaptee: adaptee)
adapter.request()
The Bridge pattern decouples an abstraction from its implementation so that the two can vary independently.
protocol Renderer {
func render(shape: String)
}
class VectorRenderer: Renderer {
func render(shape: String) {
print("Drawing \(shape) as vector")
}
}
class RasterRenderer: Renderer {
func render(shape: String) {
print("Drawing \(shape) as raster")
}
}
class Shape {
let renderer: Renderer
init(renderer: Renderer) {
self.renderer = renderer
}
func draw() {
fatalError("Subclasses must implement this method")
}
}
class Circle: Shape {
func draw() {
renderer.render(shape: "circle")
}
}
// Usage
let vectorRenderer: Renderer = VectorRenderer()
let circle = Circle(renderer: vectorRenderer)
circle.draw()
The Composite pattern allows you to treat a group of objects as a single object. This is especially useful when you need to work with a hierarchy of objects that have the same interface.
protocol Component {
func operation()
}
class Leaf: Component {
func operation() {
print("Leaf operation")
}
}
class Composite: Component {
private var children: [Component] = []
func add(_ component: Component) {
children.append(component)
}
func remove(_ component: Component) {
children.removeAll { $0 === component }
}
func operation() {
for child in children {
child.operation()
}
}
}
// Usage
let leaf1 = Leaf()
let leaf2 = Leaf()
let composite = Composite()
composite.add(leaf1)
composite.add(leaf2)
composite.operation()
The Decorator pattern allows you to add new behavior to objects without modifying their classes. This is achieved by wrapping an object with a decorator that implements the same interface.
protocol Beverage {
func cost() -> Double
func description() -> String
}
class Coffee: Beverage {
func cost() -> Double {
return 1.0
}
func description() -> String {
return "Coffee"
}
}
class BeverageDecorator: Beverage {
private let beverage: Beverage
init(beverage: Beverage) {
self.beverage = beverage
}
func cost() -> Double {
return beverage.cost()
}
func description() -> String {
return beverage.description()
}
}
class Milk: BeverageDecorator {
override func cost() -> Double {
return super.cost() + 0.5
}
override func description() -> String {
return super.description() + ", Milk"
}
}
// Usage
let coffee: Beverage = Coffee()
let coffeeWithMilk = Milk(beverage: coffee)
print(coffeeWithMilk.description())
print(coffeeWithMilk.cost())
The Facade pattern provides a simplified interface to a complex subsystem, making it easier for clients to interact with it.
class ComplexSubsystemA {
func operationA() {
print("Operation A")
}
}
class ComplexSubsystemB {
func operationB() {
print("Operation B")
}
}
class Facade {
private let subsystemA: ComplexSubsystemA
private let subsystemB: ComplexSubsystemB
init(subsystemA: ComplexSubsystemA, subsystemB: ComplexSubsystemB) {
self.subsystemA = subsystemA
self.subsystemB = subsystemB
}
func simplifiedOperation() {
subsystemA.operationA()
subsystemB.operationB()
}
}
// Usage
let subsystemA = ComplexSubsystemA()
let subsystemB = ComplexSubsystemB()
let facade = Facade(subsystemA: subsystemA, subsystemB: subsystemB)
facade.simplifiedOperation()
The Flyweight pattern helps minimize memory usage by sharing objects with similar state, instead of creating new ones.
class Flyweight {
private let sharedState: String
init(sharedState: String) {
self.sharedState = sharedState
}
func operation(uniqueState: String) {
print("Shared state: \(sharedState), unique state: \(uniqueState)")
}
}
class FlyweightFactory {
private var flyweights: [String: Flyweight] = [:]
func getFlyweight(for key: String) -> Flyweight {
if let existingFlyweight = flyweights[key] {
return existingFlyweight
} else {
let newFlyweight = Flyweight(sharedState: key)
flyweights[key] = newFlyweight
return newFlyweight
}
}
}
// Usage
let factory = FlyweightFactory()
let flyweight1 = factory.getFlyweight(for: "shared1")
flyweight1.operation(uniqueState: "unique1")
let flyweight2 = factory.getFlyweight(for: "shared1") // Reuses existing flyweight
flyweight2.operation(uniqueState: "unique2")
The Proxy pattern provides a surrogate object that controls access to another object. This can be used for various purposes such as security, lazy loading, or remote object access.
protocol Subject {
func request()
}
class RealSubject: Subject {
func request() {
print("Real subject request")
}
}
class Proxy: Subject {
private let realSubject: RealSubject
init(realSubject: RealSubject) {
self.realSubject = realSubject
}
func request() {
if checkAccess() {
realSubject.request()
logAccess()
}
}
private func checkAccess() -> Bool {
// Perform access control checks here
print("Access granted")
return true
}
private func logAccess() {
print("Access logged")
}
}
// Usage
let realSubject = RealSubject()
let proxy: Subject = Proxy(realSubject: realSubject)
proxy.request()
By implementing these 7 powerful Structural Design Patterns in your Swift projects, you can dramatically improve the organization and flexibility of your code. These patterns will help you create clean, efficient, and scalable systems that can adapt to changing requirements with ease.
I hope you enjoyed this article, and if you have any questions, comments, or feedback, then feel free to comment here or reach out via Twitter.
Thanks for reading!
Check the next article in this series Behavioral Design Patterns in Swift.