Imagine that you are create a computer machine, if you create a class named Computer
So the initializer will be such a painful and tedious parameter monster, you will find that it is a mess.
So the builder pattern make it much clear.
class ComputerBuilder
attr_reader :computer
def initialize
@computer = Computer.new
end
def turbo(has_turbo_cpu=true)
@computer.motherboard.cpu = TurboCPU.new
end
def display=(display)
@computer.display=display
end
def memory_size=(size_in_mb)
@computer.motherboard.memory_size = size_in_mb
end
def add_cd(writer=false)
@computer.drives << Drive.new(:cd, 760, writer)
end
def add_dvd(writer=false)
@computer.drives << Drive.new(:dvd, 4000, writer)
end
def add_hard_disk(size_in_mb)
@computer.drives << Drive.new(:hard_disk, size_in_mb, true)
end
end
builder = ComputerBuilder.new
builder.turbo
builder.add_cd(true)
builder.add_dvd
builder.add_hard_disk(100000)
computer = builder.computer
Builders not only ease the burden of creating complex objects, but also hide the implementation details.
We can create different kind of computer use polymorphic
class DesktopComputer < Computer
# Lots of interesting desktop details omitted...
end
class LaptopComputer < Computer
def initialize( motherboard=Motherboard.new, drives=[] )
super(:lcd, motherboard, drives)
end
# Lots of interesting laptop details omitted...
end
class ComputerBuilder
attr_reader :computer
def turbo(has_turbo_cpu=true)
@computer.motherboard.cpu = TurboCPU.new
end
def memory_size=(size_in_mb)
@computer.motherboard.memory_size = size_in_mb
end
end
class DesktopBuilder < ComputerBuilder
def initialize
@computer = DesktopComputer.new
end
def display=(display)
@display = display
end
def add_cd(writer=false)
@computer.drives << Drive.new(:cd, 760, writer)
end
def add_dvd(writer=false)
@computer.drives << Drive.new(:dvd, 4000, writer)
end
def add_hard_disk(size_in_mb)
@computer.drives << Drive.new(:hard_disk, size_in_mb, true)
end
end
class LaptopBuilder < ComputerBuilder
def initialize
@computer = LaptopComputer.new
end
def display=(display)
raise "Laptop display must be lcd" unless display == :lcd
end
def add_cd(writer=false)
@computer.drives << LaptopDrive.new(:cd, 760, writer)
end
def add_dvd(writer=false)
@computer.drives << LaptopDrive.new(:dvd, 4000, writer)
end
def add_hard_disk(size_in_mb)
@computer.drives << LaptopDrive.new(:hard_disk, size_in_mb, true)
end
end
we can encapsulate the @computer with a method to validate the computer object:
def computer
raise "Not enough memory" if @computer.motherboard.memory_size < 250
raise "Too many drives" if @computer.drives.size > 4
hard_disk = @computer.drives.find {|drive| drive.type == :hard_disk}
raise "No hard disk." unless hard_disk
@computer
end