Swift Design Patterns in Practice: the Decorator Pattern
Tags: ios, swift, designpatterns, rest
Published: 2019-06-03 13:54:17

---
title: Swift Design Patterns in Practice: the Decorator Pattern
published: true
description: 
tags: iOS, Swift, Design Patterns, REST
canonical_url: https://stablekernel.com/swift-design-patterns-in-practice-the-decorator-pattern/
---

Welcome to the first publication of “Swift Design Patterns in Practice”, a series with the goal of going beyond abstract examples by providing concrete use-cases of design patterns in real-world iOS applications. Today we will cover the Decorator Pattern and how it may be used when implementing the repo layer of an iOS application to interact with a RESTful API and a caching mechanism. The repo layer is an implementation of the [Repository Design Pattern](https://medium.com/@pererikbergman/repository-design-pattern-e28c0f3e4a30) and serves the purpose of abstracting all interactions with our entity layer. We will give a general overview of the decorator pattern, including its structure, applications, and benefits. Then we will walk through a repo layer implementation for a single resource type for a mock environment with mock implementations and a production environment with HTTP and caching layer implementations. Before we get started, I wanted to give a shoutout to [Stable Kernel](https://stablekernel.com/about-us/) for giving me time to work on these blog posts. Okay, let's get started!

## Overview

The decorator pattern allows you to dynamically and transparently add or extend functionality of an object. The main idea is to provide an interface for some object (component) that you “wrap” or decorate via constructor injection with objects that implement the same interface (decorators). You then use decorators in place of the original object because they share a common interface (yay polymorphism). This allows the decorators to modify the functionality of the component without changing any of its code at runtime. For people who like diagrams, here’s a diagram:

![Decorator Pattern Diagram](https://thepracticaldev.s3.amazonaws.com/i/6tz1wb510231ds6v5w5l.png)

## Benefits
#### Alternative to inheritance
Inheritance creates unnecessary coupling between the subclass and superclass. When changes are made to the superclass, they can break expected behavior in the subclass. Inheritance tends to be a suboptimal solution in almost all scenarios. The decorator pattern mitigates the need to subclass by giving us the ability to inject the object to fall back on for functionality instead of being forced to use the superclass.

#### Decoupled and extensible code
The component is open for extension but closed for modification (Open Closed Principle), as functionality is added by decorating the component with a new object rather than modifying it directly. The decorators should serve a single purpose for extending the component’s functionality (Single Responsibility Principle). It is a small structural change to your code that ensures your components are decoupled and extensible.

#### Avoid class explosion from combinational domain problems
Class explosion occurs in problems where many customizations are possible, especially when the order in which these customizations are applied matters or when the customizations depend on other customizations for their functionality, causing the class hierarchy to grow exponentially for each new customization added. This [post](https://dzone.com/articles/is-inheritance-dead) gives an in depth look at an exploding class hierarchy but that's not the focus of this post so we'll leave it at that.

#### Compiler-enforced type checking for objects that can change dynamically at runtime
The component is an interface. As a result, any component (decorated or not) may safely be used where this interface is used. When the component interface is changed, the compiler will yell at you until functionality is defined in all concrete components and decorators for any changes made.

#### Testing individual units of functionality
It becomes very easy to test individual concrete components or decorators because functionality is isolated. Mock concrete components can be used to test the functionality of a single decorator and tests may be reused for different combinations of decorated components. 
	
## Use Case: the Repo Layer
	
Previously, I would use a single object to hold all my network calls. Each function would be responsible for hitting the API, parsing the response, caching the data, and returning the result. This approach is rigid and scales horribly. As more calls are added this file grows and grows. You find yourself organizing these functions into clusters relating to the HTTP methods (GET, POST, PUT, DELETE, etc…) for a particular resource. This is a good sign that these functions actually belong in separate classes entirely. Enter the repo layer. In our implementation we will create a repo for accessing each resource type. A repo is meant to mirror the HTTP methods  at a given URL path. 

### Implementation
	
We will look at an implementation for a single `Post` resource at the `/posts[/:id]` route. limiting our implementation to only creating and fetching post objects (GET and POST methods) for brevity's sake. Let's start with our `Post` struct:

```swift
// If we put our initializers in extensions
// this object will maintain its automatically 
// synthesized initializer
struct Post: Codable {
	let id: Int
	let title: String
	let body: String
}
```

The decorator pattern starts with an interface. Our `PostRepo` protocol will define a `getPost(id:completion:)` and `createPost(title:body:completion:)`, using a closure and a generic `Result` type to asynchronously handle both the success and error states for each request. This same concept applies using Observables, Futures, Promises, etc... 

```swift
// Result.swift
enum Result<T> {
	case value(T)
	case error(Error)
}

// PostRepo.swift
protocol PostRepo {
	func getPost(id: Int, completion: (Result<Post>) -> Void)
	func createPost(title: String, body: String, completion: (Result<Post>) -> Void)
}
```

We can mock this out with very little effort. We no longer have to wait around on the backend team to implement the endpoints we need to do our job.

```swift
// An in-memory mock repo
class MockPostRepo: PostRepo {

	private var id = 0
	private var posts: [Int: Post] = [:]

	func getPost(id: Int, completion: (Result<Post>) -> Void) {

		if let post = posts[id] {
			// The post exists in memory
			completion(.value(post))
		} else {
			let error = NSError(domain: "Network error", code: 1, userInfo: nil) // 404 presumably
			completion(.error(error))
		}
	}

	func createPost(title: String, body: String, completion: (Result<Post>) -> Void) {
		let post = Post(id: id, title: title, body: body)
		posts[id] = post
		id += 1 // Like a db would autoincrement unique identifiers
		completion(.value(post))
	}
}
```

We can then initialize an instance of `PostRepo` to use in our application:

```swift
let postRepo: PostRepo = MockPostRepo()
```

At this point our repo layer is functional. Our data is mocked and we are ready to build our UI. The `postRepo` can now be injected into a view controller, view model, coordinator, or any architecture component.

```swift
/// For displaying a single post by id
class PostViewController: UIViewController {

	@IBOutlet weak var titleLabel: UILabel!
	@IBOutlet weak var bodyTextView: UITextView!

	private let postRepo: PostRepo
	private let postId: Int

	init(postRepo: PostRepo, postId: Int) {
		self.postRepo = postRepo
		self.postId = postId
		super.init(nibName: nil, bundle: nil)
	}

	required init?(coder aDecoder: NSCoder) { ... }

	override func viewDidLoad() {
		super.viewDidLoad()
		loadPost()
	}

	private func loadPost() {
		// We don't care if the post comes from a cache or
		// the network, only if we have one to display. Any
		// cache invalidation policy should be abstracted
		// away from us.
		postRepo.getPost(id: postId) { [weak self] result in
			switch result {
			case .value(let post):
				self?.update(with: post)
			case .error(let error):
				// Present error
			}
		}
	}

	private func update(with post: Post) {
		titleLabel.text = post.title
		bodyTextView.text = post.body
	}
}
``` 

Our view controller is dependent on an abstraction, the `PostRepo` protocol, rather than any concrete implementation of it (Dependency Inversion Principle). 

Now if we think about our caching layer, it is a fundamentally different entity than our repo layer. Our repo layer has one method to get a post asynchronously, but our caching layer needs to be able to store a post and fetch a cached post synchronously. We could easily make a concrete `PostRepo` decorator to perform caching, but we can abstract our caching layer even more by using a `PostCache` protocol to define an interface for our caching layer and a `PostRepo` decorator that is impartial to the particular cache that is used. Here is our `PostCacheProtocol`:

```swift
protocol PostCache {
	func getPost(id: Int) -> Post?
	func store(post: Post)
}
```

Once again, this is very easy to mock out. With little to no effort we can make a concrete, in-memory implementation of `PostCache`:

```swift
// An in-memory post cache
class MockPostCache: PostCache {

	private var posts: [Int: Post] = [:]

	func getPost(id: Int) -> Post? {
		return posts[id]
	}

	func store(post: Post) {
		posts[post.id] = post
	}
}
```

Now we will look into decorating a `PostRepo` with a caching layer. To do this, we will define our abstract decorator by implementing a protocol that extends the `PostRepo` protocol (Component) and holds a reference to some inner `PostRepo` object. This step is entirely optional when implementing the decorator pattern. It is not out of the ordinary to create concrete decorators that conform to `PostRepo` and have an inner `PostRepo ` property but then we must implement every  `PostRepo` function for every concrete decorator in place of an abstract decorator.
	
With Swift, we use protocol extensions to provide reasonable defaults so it is not necessary to reimplement the functions that are not applicable to a particular decorator. Our protocol extension will have the default functionality of proxying all the calls to to the inner `Component` object. This behaves similarly to providing non-abstract functions in languages that have abstract classes or using mix-ins.

```swift
// MARK: - Abstract Decorator
protocol PostRepoDecorator: PostRepo {
	var inner: PostRepo { get }
}

// Forward all calls to the inner object by default
extension PostRepoDecorator {
	func getPost(id: Int, completion: (Result<Post>) -> Void) {
		inner.getPost(id: id, completion: completion)
	}

	func createPost(title: String, body: String, completion: (Result<Post>) -> Void) {
		inner.createPost(title: title, body: body, completion: completion)
	}
}
```

```swift
class PostRepoCacheDecorator: PostRepoDecorator {

	private let cache: PostCache
	let inner: PostRepo

	init(inner: PostRepo, cache: PostCache) {
		self.inner = inner
		self.cache = cache
	}

	func getPost(id: Int, completion: (Result<Post>) -> Void) {

		guard let cachedPost = cache.getPost(id: id) else {

			// Hit the network to get posts
			return inner.getPost(id: id) { result in

				// Cache posts from network for next time
				if case .value(let post) = result {
					cache.store(post: post)
				}

				// Forward the result
				completion(result)
			}
		}

		completion(.value(cachedPost))
	}

	func createPost(title: String, body: String,
					completion: (Result<Post>) -> Void) {

		inner.createPost(title: title, body: body) { result in

			// Cache the newly created post
			if case .value(let createdPost) = result {
				cache.store(post: createdPost)
			}

			// Forward the response
			completion(result)
		}
	}
}
```

We use this `PostRepoCacheDecorator` to dynamically attach the functionality of caching to any `PostRepo` type by wrapping an existing `PostRepo` object and some `PostCache` object. Now when we set up our post repo, we are indifferent to the `PostRepo` and the `PostCache` we are using:

```swift
let cache = MockPostCache()
let api = MockPostRepo()
let postRepo: PostRepo = PostRepoCacheDecorator(inner: api, cache: cache)
```

We now have a post repo with a mocked out API and an in-memory cache. If we want to implement a non-mock cache and API repo, all we need to do is create more concrete implementations of `PostRepo` and `PostCacheProtocol`. The only existing code that will change is where we originally setup the `PostRepo` instance that we will use throughout our application. We can test the new implementations independently and we do not have to refactor the existing implementations to add the desired functionality.

Let’s make an `HttpPostRepo` to make our network calls and a `UserDefaultsPostCache` to persist data between app launches.

```swift
// Some abstraction around URLSession
protocol HttpClient {
	func get<T: Codable>(_ path: String, completion: (Result<T>) -> Void)
	func post<T: Codable>(_ path: String, body: [String: Any], completion: (Result<T>) -> Void)
	// put, delete...
}

class HttpPostRepo: PostRepo {

	private let http: HttpClient

	init(http: HttpClient) {
		self.http = http
	}

	func getPost(id: Int, completion: (Result<Post>) -> Void) {
		http.get("/posts/\(id)", completion: completion)
	}

	func createPost(title: String, body: String, completion: (Result<Post>) -> Void) {

		let httpBody: [String: Any] = [
			"title": title,
			"body": body
		]

		http.post("/posts", body: httpBody, completion: completion)
	}
}
```

```swift
class UserDefaultsPostCache: PostCache {

	private let defaults: UserDefaults

	init(defaults: UserDefaults) {
		self.defaults = defaults
	}

	// MARK: - PostCache

	func store(post: Post) {
		let encoder = JSONEncoder()
		if let encoded = try? encoder.encode(post) {
			defaults.set(encoded, forKey: keyForPost(with: post.id))
		}
	}

	func getPost(id: Int) -> Post? {
		let decoder = JSONDecoder()
		let data = defaults.object(forKey: keyForPost(with: id)) as? Data
		return data.flatMap { try? decoder.decode(Post.self, from: $0) }
	}

	// MARK: - Helpers
	private func keyForPost(with id: Int) -> String {
		return "kPostKey:\(id)"
	}
}
```

This becomes especially useful when dealing with future change. We could implement concrete `PostCache` classes for Core Data, Realm, or SQLite and it would take one line of code to integrate them into our application. 

```swift
let defaults: UserDefaults = .standard
let httpClient: HttpClient = // ...

lazy var postRepo: PostRepo = {
	let cache = UserDefaultsPostCache(defaults: defaults)
	let api = HttpPostRepo(http: httpClient)
	return PostRepoCacheDecorator(inner: api, cache: cache)
}()
```

And that’s really all there is to it. We now have an implementation agnostic repo layer that does not tie us down to any framework, library, or dependency. The Xcode project containing mock and production scheme configurations, all this source code, and a sample playground can be found on [GitHub](https://github.com/stablekernel/swift-repo-layer-example).