Builder class 负责将所有的部件瓶装于一个复杂的对象中。
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
14.2 生成器模式 UML 类图:
14.3应用场景:
1 、当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
2 、当构造过程必须允许被构造的对象有不同的表示时。
14.4生成器模式分析与实现(ruby 描述):
class Computer
attr_accessor :display
attr_accessor :motherboard
attr_accessor :drives
def initialize(display=:crt, motherboard=Motherboard.new, drives=[])
@motherboard = motherboard
@display = display
@drives = drives
end
end
class CPU
end
class TurboCPU < CPU
end
class BasicCPU < CPU
end
class Motherboard
attr_accessor :cpu
attr_accessor :memory_size
def initialize(cpu=BasicCPU.new,memory_size=1000)
@cpu = cpu
@memory_size =memory_size
end
end
class Drive
attr_reader :type
attr_reader :size
attr_reader :writable
def initialize(type, size, writable)
@type = type
@size = size
@writable = writable
end
end
#
# 这是我们来创建一台非常好的计算机
#
motherboard = Motherboard.new(TurboCPU.new,4000)
drives = []
drives << Drive.new(:hard_drive, 200000,true)
drives << Drive.new(:hard_drive, 200000,true)
drives << Drive.new(:hard_drive, 200000,true)
drives << Drive.new(:cd, 200,true)
computer = Computer.new(:lcd,motherboard,drives)
#
# 这时,我们可能还没有发现问题,因为我们才刚刚创建了一台电脑,比如我们现在要开网吧,我们需要一百台点配置不同的电脑,我想大家就要挠头了
# 现在看看我们用生成器会带来什么好处吧
#
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_work,size_in_mb,true)
end
end
builder = ComputerBuilder.new
builder.turbo
builder.add_cd(true)
builder.add_dvd
builder.add_hard_disk(1000000000)
computer = builder.computer
#
# 通过电脑生成器,我们可以生成我们想要的电脑的了,就想我们去组装店一样,告诉他们我们想要的配置,他们安装我的要求,不一会就帮我组装了
# 我想要的电脑,真实太棒了,在RUBY中有种魔法方法来写错的生成器,我们来看看吧
#
def method_missing(name, *args)
words = name.to_s.split("_")
return super(name, *args) unless words.shift == 'add'
words.each do |word|
next if word == 'and'
add_cd if word == 'cd'
add_dvd if word== 'dvd'
add_hard_disk if word == 'harddisk'
turbo if word == 'turbo'
end
end
builder.add_dvd_cd_harddisk
# or
builder.add_turbo_and_dvd_harddisk
#
# 魔法方法最杰出的应用是ActiveRecord中的查询方法
# Employee.find_by_ssn('123-34-333')
#
# Employee.find_by_firstname_and_lastname('John', 'Smith')