Definition
The ‘Factory Method’ pattern is a creational design pattern, abstracting the creation process. The creative model controls who creates an object and what / how / when it is created.
The ‘Factory Method’ pattern defines the interface to create objects and delegates the creation of objects to subclasses.
When should we use this pattern?
Provide interface to create objects
This pattern should be used when we have many different objects that we use in different ways. Their initializations can be complex and require calculation to create them. The ‘Factory Method’ pattern encapsulates their initials to simplify their creation on location.
Defining a unique place to initialize this pattern should be used when a class cannot predict the type of object it needs to create. If we have an object that does what we need, we have to reuse and initialize it somewhere in the code. Moving these instances, from the client layer to an interface, makes the class dependent on abstraction and does not make it dependent on low-level components (Dependency Reversal Principle). This interface, called the factory method, has the logic to determine the type of object we need to initialize. Furthermore, delegating the logic to a subclass will avoid code duplication and provide a single place to maintain.
To isolate the implementation of an object from its use
This pattern should be used when the creation and initialization logic is performed by the client. A client is closely associated with an object if its type is used in its class. By moving logic and initializing objects in a subclass, we protect the code from API changes. If some modifications are added to a specific class and its API, the client code will not be affected by changes that it does not care about. By implementing an interface, the factory method returns an abstraction rather than a specific type so that we protect the code from implementation details.
How should we use this pattern?
Let’s start with a common approach for this model. In this example, we are working on a mobile application and we want to create a factory method that is responsible for creating UI components.
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 | <span class="token keyword">class</span> <span class="token class-name">ComponentFactory</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">init</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">static</span> <span class="token keyword">func</span> <span class="token function">createView</span> <span class="token punctuation">(</span> component <span class="token punctuation">:</span> <span class="token builtin">ComponentType</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token builtin">UIView</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span> component <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> textfield <span class="token punctuation">:</span> <span class="token keyword">let</span> textfield <span class="token operator">=</span> <span class="token function">UITextField</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token comment">// textfield customatization...</span> <span class="token keyword">return</span> textfield <span class="token keyword">case</span> <span class="token punctuation">.</span> <span class="token keyword">switch</span> <span class="token punctuation">:</span> <span class="token keyword">let</span> ` <span class="token keyword">switch</span> ` <span class="token operator">=</span> <span class="token function">UISwitch</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token comment">// `switch` customatization...</span> <span class="token keyword">return</span> ` <span class="token keyword">switch</span> ` <span class="token keyword">case</span> <span class="token punctuation">.</span> button <span class="token punctuation">:</span> <span class="token keyword">let</span> button <span class="token operator">=</span> <span class="token function">UIButton</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token comment">// button customatization...</span> <span class="token keyword">return</span> button <span class="token keyword">case</span> <span class="token punctuation">.</span> label <span class="token punctuation">:</span> <span class="token keyword">let</span> label <span class="token operator">=</span> <span class="token function">UILabel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token comment">// label customatization...</span> <span class="token keyword">return</span> label <span class="token keyword">case</span> <span class="token punctuation">.</span> image <span class="token punctuation">:</span> <span class="token keyword">let</span> image <span class="token operator">=</span> <span class="token function">UIImageView</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token comment">// image customatization...</span> <span class="token keyword">return</span> image <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Implementation
Factory Method
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <span class="token keyword">protocol</span> <span class="token builtin">ComponentFactory</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">createView</span> <span class="token punctuation">(</span> component <span class="token punctuation">:</span> <span class="token builtin">ComponentType</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token builtin">UIView</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">DisneyComponentFactory</span> <span class="token punctuation">:</span> <span class="token builtin">ComponentFactory</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">createView</span> <span class="token punctuation">(</span> component <span class="token punctuation">:</span> <span class="token builtin">ComponentType</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token builtin">UIView</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span> component <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> textfield <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token function">DisneyTextField</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> <span class="token keyword">switch</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token function">DisneySwitch</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> button <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token function">DisneyButton</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> label <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token function">DisneyLabel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> image <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token function">DisneyImageView</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Run code in a Playground
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 | <span class="token comment">// ‼️ This online playground is platform agnostic, so we need to declare a UIView interface and its subclasses.</span> <span class="token keyword">protocol</span> <span class="token builtin">UIView</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">UITextField</span> <span class="token punctuation">:</span> <span class="token builtin">UIView</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">UISwitch</span> <span class="token punctuation">:</span> <span class="token builtin">UIView</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">UIButton</span> <span class="token punctuation">:</span> <span class="token builtin">UIView</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">UILabel</span> <span class="token punctuation">:</span> <span class="token builtin">UIView</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">UIImageView</span> <span class="token punctuation">:</span> <span class="token builtin">UIView</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">DisneyTextField</span> <span class="token punctuation">:</span> <span class="token builtin">UITextField</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">DisneySwitch</span> <span class="token punctuation">:</span> <span class="token builtin">UISwitch</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">DisneyButton</span> <span class="token punctuation">:</span> <span class="token builtin">UIButton</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">DisneyLabel</span> <span class="token punctuation">:</span> <span class="token builtin">UILabel</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">DisneyImageView</span> <span class="token punctuation">:</span> <span class="token builtin">UIImageView</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">enum</span> <span class="token builtin">ComponentType</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> textfield <span class="token keyword">case</span> ` <span class="token keyword">switch</span> ` <span class="token keyword">case</span> button <span class="token keyword">case</span> label <span class="token keyword">case</span> image <span class="token punctuation">}</span> <span class="token keyword">protocol</span> <span class="token builtin">ComponentFactory</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">createView</span> <span class="token punctuation">(</span> component <span class="token punctuation">:</span> <span class="token builtin">ComponentType</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token builtin">UIView</span> <span class="token punctuation">}</span> <span class="token keyword">class</span> <span class="token class-name">DisneyComponentFactory</span> <span class="token punctuation">:</span> <span class="token builtin">ComponentFactory</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">createView</span> <span class="token punctuation">(</span> component <span class="token punctuation">:</span> <span class="token builtin">ComponentType</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token builtin">UIView</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span> component <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> textfield <span class="token punctuation">:</span> <span class="token function">print</span> <span class="token punctuation">(</span> <span class="token string">"DisneyTextField created"</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">DisneyTextField</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> <span class="token keyword">switch</span> <span class="token punctuation">:</span> <span class="token function">print</span> <span class="token punctuation">(</span> <span class="token string">"DisneySwitch created"</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">DisneySwitch</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> button <span class="token punctuation">:</span> <span class="token function">print</span> <span class="token punctuation">(</span> <span class="token string">"DisneyButton created"</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">DisneyButton</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> label <span class="token punctuation">:</span> <span class="token function">print</span> <span class="token punctuation">(</span> <span class="token string">"DisneyLabel created"</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">DisneyLabel</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> image <span class="token punctuation">:</span> <span class="token function">print</span> <span class="token punctuation">(</span> <span class="token string">"DisneyImageView created"</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">DisneyImageView</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// Client</span> <span class="token keyword">let</span> disneyFactory <span class="token operator">=</span> <span class="token function">DisneyComponentFactory</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> disneyFactory <span class="token punctuation">.</span> <span class="token function">createView</span> <span class="token punctuation">(</span> component <span class="token punctuation">:</span> <span class="token punctuation">.</span> label <span class="token punctuation">)</span> |