Author: David Martinez
Created: May 6, 2024 - Updated: May 8, 2024
Read Time: 10 min
Welcome! Today, let's embark on a journey into the Abstract Factory design pattern. We'll dive deep into its workings, explore real-world scenarios, and unveil its magic!
The Abstract Factory is a creational design pattern that furnishes an interface for creating families of related or dependent objects without specifying their concrete classes.
This pattern revolves around a super-factory, known as an Abstract Factory, which generates other factories. These factories, in turn, produce objects related to specific families.
๐ธ Use this pattern when your code needs to interact with various families of related products, yet you prefer not to bind it to the concrete classes of those products.
๐ธ It's beneficial when providing a library of classes for users to extend.
Consider developing a native application intended for multiple operating systems like Windows, Mac, and Linux. This application incorporates various UI elements such as buttons, inputs, text areas, and dialogs.
Rendering these UI elements in accordance with each operating system's style poses a challenge. Additionally, avoiding code alterations whenever a new OS is supported is crucial.
The Abstract Factory pattern suggests creating separate factory interfaces for each UI element type, like buttons, inputs, text areas, etc. Each factory interface defines methods to create these UI elements, returning abstract products such as Button, Input, Textarea, etc.
Further, interfaces are declared for each distinct product of the UI elements, such as Button, Input, Textarea, etc., with common methods. Concrete factories implement these interfaces and produce concrete products like WindowsButton, WindowsInput, WindowsTextarea, MacButton, MacInput, MacTextarea, etc. In this example, the Abstract Factory pattern is utilized to create UI elements for Windows and Mac operating systems.
๐น The Abstract Factory interface declares factory methods to create UI elements like createButton, createInput, createTextarea, etc.
๐น Concrete factories implement these factory methods to create OS-specific UI elements.
๐น Concrete products implement UI element interfaces like Button, Input, Textarea, etc.
๐น Client code utilizes the Abstract Factory interface to create UI elements without knowledge of their concrete classes.
๐น All UI elements are treated uniformly by client code, regardless of their concrete class.
๐น Client code is aware of the render method in all UI elements but doesn't concern itself with how it's implemented in each concrete class.
1๏ธโฃ Concrete products implement UI element interfaces like Button, Input, Textarea, etc.
2๏ธโฃ Concrete factories implement the Abstract Factory interface, producing concrete products tailored to specific OSes.
3๏ธโฃ The Abstract Factory interface declares factory methods for creating UI elements like createButton, createInput, createTextarea, etc.
4๏ธโฃ Abstract factories spawn concrete factories that adhere to the Abstract Factory interface.
๐ก Note: The abstract factory can optimize by reusing existing objects rather than creating new ones every time.
๐ฎ Ensures compatibility among products obtained from a factory.
๐ฎ Avoids tight coupling between concrete products and client code.
๐ฎ Facilitates seamless replacement of the entire product family by switching concrete factories.
๐ฎ Enables introducing new product variants without disrupting existing client code.
๐ฎ Aligns with the Open/Closed Principle by extending the codebase with new classes instead of modifying existing ones.
๐ฎ Adheres to the Single Responsibility Principle by consolidating product creation in one place, enhancing code maintainability.
# GUIFactory "Interface"# (since interfaces does not exist in Ruby, we will use a module to define the interface)module GUIFactorydef create_buttonraise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"enddef create_checkboxraise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"endendclass WinFactoryinclude GUIFactorydef create_buttonWindowsButton.newenddef create_checkboxWindowsCheckbox.newendendclass MacFactoryinclude GUIFactorydef create_buttonMacButton.newenddef create_checkboxMacCheckbox.newendend# Checkboxmodule Checkboxdef renderraise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"enddef on_changeraise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"endendclass MacCheckboxinclude Checkboxdef renderputs 'MacCheckbox render'enddef on_changeputs 'MacCheckbox on_change'endendclass WindowsCheckboxinclude Checkboxdef renderputs 'WindowsCheckbox render'enddef on_changeputs 'WindowsCheckbox on_change'endend# Buttonmodule Buttondef renderraise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"enddef on_clickraise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"endendclass MacButtoninclude Buttondef renderputs 'MacButton render'enddef on_clickputs 'MacButton on_click'endendclass WindowsButtoninclude Buttondef renderputs 'WindowsButton render'enddef on_clickputs 'WindowsButton on_click'endend# Applicationclass Applicationdef initialize(factory)@factory = factoryenddef create_uibutton = @factory.create_buttoncheckbox = @factory.create_checkboxbutton.rendercheckbox.renderendend# Clientdef mainop_system = 'mac'if op_system == 'win'factory = WinFactory.newelsefactory = MacFactory.newendapp = Application.new(factory)app.create_uiend# OutputMacButton renderMacCheckbox render
The Abstract Factory pattern furnishes an interface for creating families of related or dependent objects without specifying their concrete classes.
๐บ This pattern is advantageous when your code interacts with various families of related products without relying on their concrete classes.
๐บ It's beneficial when providing a library of classes for users to extend.
๐บ It ensures compatibility among products obtained from a factory, avoids tight coupling between concrete products and client code, and facilitates seamless replacement of the entire product family.
๐บ The Abstract Factory pattern aligns with the Open/Closed Principle by extending the codebase with new classes instead of modifying existing ones.
๐ป You can find this and other design patterns here ๐