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