Difficulty: Beginner | Easy | Normal | Challenging
Xcode 14.0.1
Swift 5.7
1. About
In this article, I will introduce to you a Fundamental Design Pattern – Builder Pattern. So what is the Builder Pattern like, its application and how to install it?
As usual, I won’t talk about theory/definition right away. I will show an example of the Builder Pattern first, then we will dive into its essence!!!
2. Make a problem
I have an example of creating a URLRequest for calling API https://api.themoviedb.org/3/movie/upcoming?api_key=7cdeb275d08259b817a3b80a7ff85f15
as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <span class="token keyword">class</span> <span class="token class-name">URLRequestHelper</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">var</span> components <span class="token operator">=</span> <span class="token class-name">URLComponents</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">private</span> <span class="token keyword">var</span> httpMethod <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"GET"</span></span> <span class="token keyword">private</span> <span class="token keyword">var</span> headers <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token class-name">String</span> <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">:</span> <span class="token punctuation">]</span> <span class="token keyword">private</span> <span class="token keyword">var</span> body <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token class-name">String</span> <span class="token punctuation">:</span> <span class="token keyword">Any</span> <span class="token punctuation">]</span> <span class="token operator">?</span> <span class="token keyword">init</span> <span class="token punctuation">(</span> baseUrl <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"https://api.themoviedb.org"</span></span> <span class="token punctuation">,</span> path <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span> <span class="token punctuation">,</span> queryItems <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token class-name">String</span> <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">:</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> httpMethod <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"GET"</span></span> <span class="token punctuation">,</span> headers <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token class-name">String</span> <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">:</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> body <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token class-name">String</span> <span class="token punctuation">:</span> <span class="token keyword">Any</span> <span class="token punctuation">]</span> <span class="token operator">?</span> <span class="token operator">=</span> <span class="token nil constant">nil</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> components <span class="token operator">=</span> <span class="token class-name">URLComponents</span> <span class="token punctuation">(</span> string <span class="token punctuation">:</span> baseUrl <span class="token punctuation">)</span> <span class="token operator">!</span> <span class="token keyword">var</span> path <span class="token operator">=</span> path <span class="token keyword">if</span> <span class="token operator">!</span> path <span class="token punctuation">.</span> <span class="token function">hasPrefix</span> <span class="token punctuation">(</span> <span class="token string-literal"><span class="token string">"/"</span></span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> path <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"/"</span></span> <span class="token operator">+</span> path <span class="token punctuation">}</span> components <span class="token punctuation">.</span> path <span class="token operator">=</span> path components <span class="token punctuation">.</span> queryItems <span class="token operator">=</span> queryItems <span class="token punctuation">.</span> map <span class="token punctuation">{</span> key <span class="token punctuation">,</span> value <span class="token keyword">in</span> <span class="token class-name">URLQueryItem</span> <span class="token punctuation">(</span> name <span class="token punctuation">:</span> key <span class="token punctuation">,</span> value <span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"</span> <span class="token interpolation-punctuation punctuation">(</span> <span class="token interpolation">value</span> <span class="token interpolation-punctuation punctuation">)</span> <span class="token string">"</span></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> components <span class="token punctuation">.</span> percentEncodedQuery <span class="token operator">=</span> components <span class="token punctuation">.</span> percentEncodedQuery <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">replacingOccurrences</span> <span class="token punctuation">(</span> of <span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"+"</span></span> <span class="token punctuation">,</span> with <span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"%2B"</span></span> <span class="token punctuation">)</span> <span class="token keyword">self</span> <span class="token punctuation">.</span> httpMethod <span class="token operator">=</span> httpMethod <span class="token keyword">self</span> <span class="token punctuation">.</span> headers <span class="token operator">=</span> headers <span class="token keyword">self</span> <span class="token punctuation">.</span> body <span class="token operator">=</span> body <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function-definition function">build</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">URLRequest</span> <span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token keyword">guard</span> <span class="token keyword">let</span> url <span class="token operator">=</span> components <span class="token punctuation">.</span> url <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token nil constant">nil</span> <span class="token punctuation">}</span> <span class="token keyword">var</span> request <span class="token operator">=</span> <span class="token class-name">URLRequest</span> <span class="token punctuation">(</span> url <span class="token punctuation">:</span> url <span class="token punctuation">)</span> request <span class="token punctuation">.</span> httpMethod <span class="token operator">=</span> httpMethod request <span class="token punctuation">.</span> <span class="token function">setValue</span> <span class="token punctuation">(</span> <span class="token string-literal"><span class="token string">"application/json"</span></span> <span class="token punctuation">,</span> forHTTPHeaderField <span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Content-Type"</span></span> <span class="token punctuation">)</span> request <span class="token punctuation">.</span> <span class="token function">setValue</span> <span class="token punctuation">(</span> <span class="token string-literal"><span class="token string">"application/json"</span></span> <span class="token punctuation">,</span> forHTTPHeaderField <span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Accept"</span></span> <span class="token punctuation">)</span> headers <span class="token punctuation">.</span> forEach <span class="token punctuation">{</span> request <span class="token punctuation">.</span> <span class="token function">addValue</span> <span class="token punctuation">(</span> <span class="token short-argument">$0</span> <span class="token punctuation">.</span> value <span class="token punctuation">,</span> forHTTPHeaderField <span class="token punctuation">:</span> <span class="token short-argument">$0</span> <span class="token punctuation">.</span> key <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token keyword">let</span> body <span class="token operator">=</span> body <span class="token punctuation">{</span> <span class="token keyword">let</span> jsonData <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token operator">?</span> <span class="token class-name">JSONSerialization</span> <span class="token punctuation">.</span> <span class="token function">data</span> <span class="token punctuation">(</span> withJSONObject <span class="token punctuation">:</span> body <span class="token punctuation">,</span> options <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> request <span class="token punctuation">.</span> httpBody <span class="token operator">=</span> jsonData <span class="token punctuation">}</span> <span class="token keyword">return</span> request <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Don’t worry if you can’t understand the entire code above. The main content of the above code is that we have a class URLRequestHelper
that has a build() function that returns a URLRequest for us. We just need to get the result (this URLRequest) to make the API call:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">let</span> request <span class="token operator">=</span> <span class="token class-name">URLRequestHelper</span> <span class="token punctuation">(</span> path <span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"3/movie/upcoming"</span></span> <span class="token punctuation">,</span> queryItems <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token string-literal"><span class="token string">"api_key"</span></span> <span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"7cdeb275d08259b817a3b80a7ff85f15"</span></span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">build</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">let</span> task <span class="token operator">=</span> <span class="token class-name">URLSession</span> <span class="token punctuation">.</span> shared <span class="token punctuation">.</span> <span class="token function">dataTask</span> <span class="token punctuation">(</span> with <span class="token punctuation">:</span> request <span class="token operator">!</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> data <span class="token punctuation">,</span> response <span class="token punctuation">,</span> error <span class="token keyword">in</span> <span class="token keyword">if</span> error <span class="token operator">!=</span> <span class="token nil constant">nil</span> <span class="token punctuation">{</span> <span class="token function">print</span> <span class="token punctuation">(</span> error <span class="token operator">!</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token keyword">let</span> returnData <span class="token operator">=</span> <span class="token class-name">String</span> <span class="token punctuation">(</span> data <span class="token punctuation">:</span> data <span class="token operator">!</span> <span class="token punctuation">,</span> encoding <span class="token punctuation">:</span> <span class="token punctuation">.</span> utf8 <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">print</span> <span class="token punctuation">(</span> returnData <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> task <span class="token punctuation">.</span> <span class="token function">resume</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> |
So we will get the list of movies from API https://api.themoviedb.org/3/movie/upcoming?api_key=7cdeb275d08259b817a3b80a7ff85f15
So what’s wrong with our URLRequestHelper
class? And why do I mention it in this article.
=> Of course our URLRequestHelper
class is perfectly fine, we can use it in most projects.
Suppose in a certain project, I want to add cachePolicy (URLRequest.CachePolicy) or timeoutInterval (TimeInterval),… how about our init function?
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">init</span> <span class="token punctuation">(</span> baseUrl <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"https://api.themoviedb.org"</span></span> <span class="token punctuation">,</span> path <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span> <span class="token punctuation">,</span> queryItems <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token class-name">String</span> <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">:</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> httpMethod <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"GET"</span></span> <span class="token punctuation">,</span> headers <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token class-name">String</span> <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">:</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> body <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token class-name">String</span> <span class="token punctuation">:</span> <span class="token keyword">Any</span> <span class="token punctuation">]</span> <span class="token operator">?</span> <span class="token operator">=</span> <span class="token nil constant">nil</span> <span class="token punctuation">,</span> cachePolicy <span class="token punctuation">:</span> <span class="token class-name">URLRequest</span> <span class="token punctuation">.</span> <span class="token class-name">CachePolicy</span> <span class="token operator">=</span> <span class="token punctuation">.</span> useProtocolCachePolicy <span class="token punctuation">,</span> timeoutInterval <span class="token punctuation">:</span> <span class="token class-name">TimeInterval</span> <span class="token operator">=</span> <span class="token number">20</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> |
The init function looks fine, right?
- What if I need to add more parameters? So our init function will become a lot complicated, right?
- What if I only need to use queryItems (like the API movie call example above)? (while we need to provide multiple parameters to the init function)
=> Of course, since we already have thedefault value
, we only need to pass the necessary parameters (that’s why the Builder Pattern can be anti-pattern, but we’ll discuss this later)
=> That’s why we have the Builder Pattern to help reduce the complexity of our initialization function (init).
=> Let’s apply the Builder Pattern to the example code above
3. Example of Builder Pattern
Still an example of creating a URLRequest to call the API https://api.themoviedb.org/3/movie/upcoming?api_key=7cdeb275d08259b817a3b80a7ff85f15
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | <span class="token keyword">class</span> <span class="token class-name">URLRequestBuilder</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">var</span> components <span class="token operator">=</span> <span class="token class-name">URLComponents</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">private</span> <span class="token keyword">var</span> httpMethod <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"GET"</span></span> <span class="token keyword">private</span> <span class="token keyword">var</span> headers <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token class-name">String</span> <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">:</span> <span class="token punctuation">]</span> <span class="token keyword">private</span> <span class="token keyword">var</span> body <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token class-name">String</span> <span class="token punctuation">:</span> <span class="token keyword">Any</span> <span class="token punctuation">]</span> <span class="token operator">?</span> <span class="token keyword">init</span> <span class="token punctuation">(</span> baseUrl <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"https://api.themoviedb.org"</span></span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> components <span class="token operator">=</span> <span class="token class-name">URLComponents</span> <span class="token punctuation">(</span> string <span class="token punctuation">:</span> baseUrl <span class="token punctuation">)</span> <span class="token operator">!</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function-definition function">setPath</span> <span class="token punctuation">(</span> <span class="token omit keyword">_</span> path <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">URLRequestBuilder</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> path <span class="token operator">=</span> path <span class="token keyword">if</span> <span class="token operator">!</span> path <span class="token punctuation">.</span> <span class="token function">hasPrefix</span> <span class="token punctuation">(</span> <span class="token string-literal"><span class="token string">"/"</span></span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> path <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"/"</span></span> <span class="token operator">+</span> path <span class="token punctuation">}</span> components <span class="token punctuation">.</span> path <span class="token operator">=</span> path <span class="token keyword">return</span> <span class="token keyword">self</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function-definition function">setQueryItems</span> <span class="token punctuation">(</span> <span class="token omit keyword">_</span> queryItems <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token class-name">String</span> <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">URLRequestBuilder</span> <span class="token punctuation">{</span> components <span class="token punctuation">.</span> queryItems <span class="token operator">=</span> queryItems <span class="token punctuation">.</span> map <span class="token punctuation">{</span> key <span class="token punctuation">,</span> value <span class="token keyword">in</span> <span class="token class-name">URLQueryItem</span> <span class="token punctuation">(</span> name <span class="token punctuation">:</span> key <span class="token punctuation">,</span> value <span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"</span> <span class="token interpolation-punctuation punctuation">(</span> <span class="token interpolation">value</span> <span class="token interpolation-punctuation punctuation">)</span> <span class="token string">"</span></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> components <span class="token punctuation">.</span> percentEncodedQuery <span class="token operator">=</span> components <span class="token punctuation">.</span> percentEncodedQuery <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">replacingOccurrences</span> <span class="token punctuation">(</span> of <span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"+"</span></span> <span class="token punctuation">,</span> with <span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"%2B"</span></span> <span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token keyword">self</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function-definition function">setHTTPMethod</span> <span class="token punctuation">(</span> <span class="token omit keyword">_</span> method <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">URLRequestBuilder</span> <span class="token punctuation">{</span> httpMethod <span class="token operator">=</span> method <span class="token keyword">return</span> <span class="token keyword">self</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function-definition function">setHeaders</span> <span class="token punctuation">(</span> <span class="token omit keyword">_</span> headers <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token class-name">String</span> <span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">URLRequestBuilder</span> <span class="token punctuation">{</span> <span class="token keyword">self</span> <span class="token punctuation">.</span> headers <span class="token operator">=</span> headers <span class="token keyword">return</span> <span class="token keyword">self</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function-definition function">setBody</span> <span class="token punctuation">(</span> <span class="token omit keyword">_</span> body <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token class-name">String</span> <span class="token punctuation">:</span> <span class="token keyword">Any</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">URLRequestBuilder</span> <span class="token punctuation">{</span> <span class="token keyword">self</span> <span class="token punctuation">.</span> body <span class="token operator">=</span> body <span class="token keyword">return</span> <span class="token keyword">self</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function-definition function">build</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">URLRequest</span> <span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token keyword">guard</span> <span class="token keyword">let</span> url <span class="token operator">=</span> components <span class="token punctuation">.</span> url <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token nil constant">nil</span> <span class="token punctuation">}</span> <span class="token keyword">var</span> request <span class="token operator">=</span> <span class="token class-name">URLRequest</span> <span class="token punctuation">(</span> url <span class="token punctuation">:</span> url <span class="token punctuation">)</span> request <span class="token punctuation">.</span> httpMethod <span class="token operator">=</span> httpMethod request <span class="token punctuation">.</span> <span class="token function">setValue</span> <span class="token punctuation">(</span> <span class="token string-literal"><span class="token string">"application/json"</span></span> <span class="token punctuation">,</span> forHTTPHeaderField <span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Content-Type"</span></span> <span class="token punctuation">)</span> request <span class="token punctuation">.</span> <span class="token function">setValue</span> <span class="token punctuation">(</span> <span class="token string-literal"><span class="token string">"application/json"</span></span> <span class="token punctuation">,</span> forHTTPHeaderField <span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Accept"</span></span> <span class="token punctuation">)</span> headers <span class="token punctuation">.</span> forEach <span class="token punctuation">{</span> request <span class="token punctuation">.</span> <span class="token function">addValue</span> <span class="token punctuation">(</span> <span class="token short-argument">$0</span> <span class="token punctuation">.</span> value <span class="token punctuation">,</span> forHTTPHeaderField <span class="token punctuation">:</span> <span class="token short-argument">$0</span> <span class="token punctuation">.</span> key <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token keyword">let</span> body <span class="token operator">=</span> body <span class="token punctuation">{</span> <span class="token keyword">let</span> jsonData <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token operator">?</span> <span class="token class-name">JSONSerialization</span> <span class="token punctuation">.</span> <span class="token function">data</span> <span class="token punctuation">(</span> withJSONObject <span class="token punctuation">:</span> body <span class="token punctuation">,</span> options <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> request <span class="token punctuation">.</span> httpBody <span class="token operator">=</span> jsonData <span class="token punctuation">}</span> <span class="token keyword">return</span> request <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
It’s much easier to understand, isn’t it, people. I can get the URLRequest from the build() function as follows:
1 2 3 4 5 | <span class="token keyword">let</span> request <span class="token operator">=</span> <span class="token class-name">URLRequestBuilder</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">setPath</span> <span class="token punctuation">(</span> <span class="token string-literal"><span class="token string">"3/movie/upcoming"</span></span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">setQueryItems</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token string-literal"><span class="token string">"api_key"</span></span> <span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"7cdeb275d08259b817a3b80a7ff85f15"</span></span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">build</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> |
Back to the problem in part 2, suppose we need to add other parameters to build the URLRequest for example: cachePolicy (URLRequest.CachePolicy) or timeoutInterval (TimeInterval), ..
We just need to create the corresponding functions, for example:
1 2 3 4 5 | <span class="token keyword">func</span> <span class="token function-definition function">setTimeoutInterval</span> <span class="token punctuation">(</span> <span class="token omit keyword">_</span> timeoutInterval <span class="token punctuation">:</span> <span class="token class-name">TimeInterval</span> <span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">URLRequestBuilder</span> <span class="token punctuation">{</span> <span class="token keyword">self</span> <span class="token punctuation">.</span> timeoutInterval <span class="token operator">=</span> timeoutInterval <span class="token keyword">return</span> <span class="token keyword">self</span> <span class="token punctuation">}</span> |
Very simple, isn’t it, people. Not only that, the Builder Pattern also helps us to comply with the S principle (in SOLID) – each function has only one task.
So we’ve gone through an example of using the Builder Pattern. We will come to the definition / theory of the Builder Pattern
3. What is the Builder Pattern?
- The Builder Pattern belongs to the Creational Design Pattern group. It will help us to create a complex object by providing each parameter, and they also increase the reusability of functions that provide parameters.
- The builder pattern allows you to create complex objects by providing inputs step- by-step, instead of requiring all inputs upfront via an initializer – Design Pattern by Tutorials
- Builder is a creational design pattern that lets you construct complex objects step by step. The pattern allows you to produce different types and representations of an object using the same construction code – Dive Into Design Pattern
Those are some definitions of the Builder Pattern. We have the following diagram:
- Builder Pattern it will include 3 parts:
- Product : Is the complex class/object that we need to instantiate (in example 2, our Product is URLRequest )
- A Builder class: It is a place to contain functions that provide parameters and a build() function that returns Product for us (here, returns URLRequest )
- Director : It can be a UIViewController or a Helper class. Where we initialize the Builder class to receive the Product (in example 2, our Director is the place to execute the code that provides the path and queryItems )
4. When to use the Builder Pattern? ️
- As mentioned above, we use the Builder Pattern to reduce the complexity when instantiating a complex class/object and we don’t need to care about the order in which the parameters are provided (like in example 2, we can provide path before queryItems or vice versa)
- Use the builder pattern when you want to create a complex object using a series of steps. – Design Patterns by Tutorials
- Use the Builder pattern to get rid of a “telescopic constructor” – Dive Into Design Pattern
- Use the Builder pattern when you want your code to be able to create different representations of some product – Dive Into Design Pattern
- Use the Builder to construct Composite trees or other complex objects – Dive Into Design Pattern
5. Pros and cons
5.1. Advantage
- We can initialize the object step by step and don’t care the order of those steps
- Functions that provide parameters can be reused
- True to the S principle (in SOLID) – Single Responsibility Principle
5.2. Defect
- The complexity of the code can increase when we need to create many new classes (provide more parameters => complexity of the Builder class increases)
6. Conclusion
- So we have learned what the Builder Pattern is and how to install it through this blog.
- If you have any questions or have a way to optimize your Builder Pattern example, don’t hesitate to comment. Thank you so much = Thank a lot = Thank you very much.
Some good examples you can refer to:
- Class Builder in MVP-CHEAP
- https://www.swiftyvn.com/2019/05/builder-design-pattern/
- https://theswiftdev.com/swift-builder-design-pattern/
- https://magz.techover.io/2021/08/02/design-pattern-builder-pattern-in-ios/
- https://github.com/ochococo/Design-Patterns-In-Swift#-builder