Author: David Martinez
Created: November 11, 2024 - Updated: November 12, 2024
Read Time: 10 min
Here, we’ll explore the Builder design pattern, a versatile tool in software engineering for managing the creation of complex objects. We'll examine its structure, benefits, and a practical use case in Ruby.
The Builder pattern is a creational design pattern that simplifies the construction of complex objects by separating the creation process into distinct steps. By breaking down object creation, it gives flexibility in how these objects are assembled, making it useful when objects require multiple configurations or components.
This pattern is ideal for scenarios where building an object requires multiple, conditional steps, like configuring a vehicle or constructing a GUI.
🔸 Use Builder when creating an object involves many optional or configurable parts.
🔸 It’s particularly useful when constructing complex objects with many combinations or when different versions of an object share similar building steps.
Imagine a manufacturing application for assembling motorcycles. Each type of motorcycle may require different parts and configurations, such as a sport model with high-performance features or a basic model with standard components.
Without a structured approach, the code becomes hard to manage, and making changes or adding new models risks introducing errors.
The Builder pattern enables us to split the construction process into distinct steps that can be reused or customized for each motorcycle type. We can apply this pattern to construct different configurations of motorcycles with the desired components and settings.
In this example, the Builder pattern helps us configure and build motorcycles with specific parts and features.
🔹 We create different builders (e.g., MotoNakedBuilder
, MotoSportBuilder
) to handle specific configurations.
🔹 A Director
class orchestrates the building process based on the motorcycle model requirements.
1️⃣ Define a Builder interface with methods for each component (e.g., set_engine
, set_gps
).
2️⃣ Implement concrete Builder classes (e.g., MotoNakedBuilder
, MotoSportBuilder
) to create configurations with different parts.
3️⃣ Use a Director to control and execute the steps for building each motorcycle type.
💡 Note: This pattern supports flexibility in object creation, allowing builders to be customized or extended as needed.
🔮 Provides flexibility in creating complex objects with optional components.
🔮 Simplifies adding new configurations or versions without altering existing code.
🔮 Separates object construction from the representation, promoting clean, modular code.
🔮 Makes it easier to implement various versions of an object that share common construction steps.
# Product classesclass MotoNakeddef initialize@parts = []enddef add(part)@parts << partenddef list_partsputs "Moto Naked parts: #{@parts.join(', ')}"endendclass MotoSportdef initialize@parts = []enddef add(part)@parts << partenddef list_partsputs "Moto Sport parts: #{@parts.join(', ')}"endend# Builder interfacemodule Builderdef resetraise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"enddef set_seatsraise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"enddef set_engineraise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"enddef set_trip_computerraise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"enddef set_gpsraise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"enddef set_break_assistraise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"endend# Concrete Builder for Naked modelclass MotoNakedBuilderinclude Builderdef initializeresetenddef reset@moto = MotoNaked.newenddef set_seats@moto.add('seats')enddef set_engine@moto.add('basic engine')enddef set_trip_computer@moto.add('trip computer')enddef set_gps@moto.add('ai gps')enddef set_break_assist@moto.add('basic break assist')enddef motomoto = @motoresetmotoendend# Concrete Builder for Sport modelclass MotoSportBuilderinclude Builderdef initializeresetenddef reset@moto = MotoSport.newenddef set_seats@moto.add('premium seats')enddef set_engine@moto.add('sport engine')enddef set_trip_computer@moto.add('trip computer')enddef set_gps@moto.add('premium gps')enddef set_break_assist@moto.add('ai break assist')enddef motomoto = @motoresetmotoendend# Director classclass Directordef build_naked_moto(builder)builder.set_seatsbuilder.set_enginebuilder.set_trip_computerenddef build_sport_moto(builder)builder.set_seatsbuilder.set_enginebuilder.set_trip_computerbuilder.set_gpsbuilder.set_break_assistendend# Client codedef maindirector = Director.newbuilder = MotoNakedBuilder.newdirector.build_naked_moto(builder)builder.moto.list_partsbuilder = MotoSportBuilder.newdirector.build_sport_moto(builder)builder.moto.list_partsendmain if __FILE__ == $PROGRAM_NAME# Output:# Moto Naked parts: seats, basic engine, trip computer# Moto Sport parts: premium seats, sport engine, trip computer, premium gps, ai break assist
The Builder pattern is a powerful solution for constructing complex objects with various configurations.
🔺 It’s ideal for creating objects with multiple optional parts or when different versions share common construction steps.
🔺 The Builder pattern helps maintain clean, modular code by separating the construction process from the object structure.
🔺 By implementing Builder, you create a flexible and extendable way to manage the creation of complex objects.
💻 You can find this and other design patterns here 📚