## 35.建造者模式
假设你正在为网站提供高度定制化功能的计算机制造商编写一款软件。 一台计算机可以有很多零件,它们可以变化,因此有很多组合。 因此,我们不是将所有这些代码放在一个单一的大型计算机类中,而是创建了一个名为 builder 的类,在这种情况下,我们创建了一个名为`ComputerBuilder`的类,该类承担创建定制计算机的任务,并可能简化创建或创建过程。 构建过程也是如此。
假设我们需要不同类型的 CPU 来构建计算机,为此,我们编写了三种类型的 CPU 类,如下所示 [cpus.rb](code/design_patterns/builder/cpus.rb) 。
```rb
```
1
2
3
4
5
6
7
8
9
10
11
```rb
|
```
class CPU
# cpu stuff...
end
class BasicCPU < CPU
# basic cpu stuff...
end
class TurboCPU < CPU
# trubo fast cpu stuff...
end
```rb
|
```
计算机可能需要驱动器,我们也为此编写了一个类,如果你看到下面的代码 [drive.rb](code/design_patterns/builder/drive.rb) ,则为该驱动器提供了一个类以及一个可用于自定义的初始化程序 在一定程度上。
```rb
```
1
2
3
4
5
6
7
8
9
```rb
|
```
class Drive
attr_reader :type, :size, :writable
def initialize(type, size, writable)
@type = type
@size = size
@writable = writable
end
end
```rb
|
```
以类似的方式,下面我们在[母板.rb](code/design_patterns/builder/motherboard.rb) 中为母板编码。
```rb
```
1
2
3
4
5
6
7
8
```rb
|
```
class Motherboard
attr_accessor :cpu, :memory_size
def initialize(cpu = BasicCPU.new, memory_size = 1000)
@cpu = cpu
@memory_size = memory_size
end
end
```rb
|
```
现在让我们看一下`Computer`类(在 [computer.rb](code/design_patterns/builder/computer.rb) 中),这与`Drive`和`Motherboard`类非常相似。 我们的目标是了解构建器模式,因此继续前进。
```rb
```
1
2
3
4
5
6
7
8
9
```rb
|
```
class Computer
attr_accessor :display, :motherboard, :drives
def initialize(display = :crt, motherboard = Motherboard.new, drives = [])
@display = display
@motherboard = motherboard
@drives = drives
end
end
```rb
|
```
现在,让我们分析一下本节的英雄`ComputerBuilder`类。 浏览下面的代码,我们将很快讨论。
```rb
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
```rb
|
```
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(writable = false)
@computer.drives << Drive.new(:cd, 760, writable)
end
def add_dvd(writable = false)
@computer.drives << Drive.new(:dvd, 4700, writable)
end
def add_hard_disk(size_in_mb)
@computer.drives << Drive.new(:hard_disk, size_in_mb, true)
end
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(100_000) if word == 'harddisk'
turbo if word == 'turbo'
end
end
def computer
raise 'Not enough memory.' if @computer.motherboard.memory_size < 250
raise 'Too many drives.' if @computer.drives.size > 4
@computer
end
end
```rb
|
```
在上面的程序中,第 4 行中确实有`initialize`方法,但是如果你查看第 44 行,则在方法`computer`中将返回`Computer`实例。 如果你看到的是同一功能,那么如果没有足够的内存,或者如果计算机中添加了太多磁盘,则我们有代码引发异常。 因此,这是构建器模式的另一个优点,在该模型中,如果不满足特定条件,就可以防止构建复杂的对象。
在构建器中,你具有`display`,`memory_size`之类的方法,以及名为`turbo`的函数来设置显示,内存和 CPU 类型的参数。 我们还具有`add_cd`,`add_dvd`和`add_hard_disk`之类的功能,可将这些内容添加到我们正在构建的计算机中。
现在让我们看一下将所有内容组合在一起的程序。 看看下面的程序 [main.rb](code/design_patterns/builder/main.rb) ,键入或复制并执行它。
```rb
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
```rb
|
```
require_relative 'cpus'
require_relative 'drive'
require_relative 'motherboard'
require_relative 'computer'
require_relative 'computer_builder'
builder = ComputerBuilder.new
builder.turbo
builder.display(:lcd)
builder.add_cd
builder.add_dvd(true)
builder.add_hard_disk(100_000)
# manufacture 10 computers using the builder
computers = []
10.times { computers << builder.computer.clone }
computers.each { |computer| puts computer }
# computer must have at least 250 MB of memory
builder = ComputerBuilder.new
builder.memory_size(249)
begin
builder.computer
rescue Exception => e
puts e.message
end
# computer must have at most 4 drives
builder = ComputerBuilder.new
builder.add_cd
builder.add_dvd
builder.add_hard_disk(1000)
builder.add_cd
builder.add_dvd
begin
builder.computer
rescue Exception => e
puts e.message
end
# use magic method to rapidly build a computer
puts 'Computer built with magic method builder'
builder = ComputerBuilder.new
builder.add_cd_and_dvd_and_harddisk_and_turbo
computer = builder.computer
puts "CPU: #{computer.motherboard.cpu.class}"
computer.drives.each { |drive| puts "Drive: #{drive.type}" }
```rb
|
```
输出量
```rb
#<Computer:0x0000564155728610>
#<Computer:0x0000564155728598>
#<Computer:0x0000564155728570>
#<Computer:0x0000564155728548>
#<Computer:0x0000564155728520>
#<Computer:0x00005641557284f8>
#<Computer:0x00005641557284d0>
#<Computer:0x00005641557284a8>
#<Computer:0x0000564155728430>
#<Computer:0x0000564155728408>
Not enough memory.
Too many drives.
Computer built with magic method builder
CPU: TurboCPU
Drive: cd
Drive: dvd
Drive: hard_disk
```
现在让我们看看它是如何工作的。 从 1-5 行:
```rb
require_relative 'cpus'
require_relative 'drive'
require_relative 'motherboard'
require_relative 'computer'
require_relative 'computer_builder'
```
我们需要该程序正常运行所需的文件。 在下面显示的以下几行中,我们创建一个名为`builder`的`ComputerBuilder`实例,该实例具有 Turbo CPU,LCD 显示屏,一个 CD 播放器,一个可写 DVD 和 100,000 MB 的硬盘:
```rb
builder = ComputerBuilder.new
builder.turbo
builder.display(:lcd)
builder.add_cd
builder.add_dvd(true)
builder.add_hard_disk(100_000)
```
现在,使用此`builder`,我们可以克隆 <sup class="footnote">[ [67](#_footnotedef_67 "View footnote.") ]</sup> 以创建任意数量的计算机。 在下面的代码中,我们创建 10 个计算机克隆并打印它们
```rb
# manufacture 10 computers using the builder
computers = []
10.times { computers << builder.computer.clone }
computers.each { |computer| puts computer }
```
| | 假设你正在编写游戏,并且需要创建 10 个对象,这种模式将非常方便。 |
现在,让我们测试如果内存不足则将引发异常的代码。 看下面的代码
```rb
# computer must have at least 250 MB of memory
builder = ComputerBuilder.new
builder.memory_size(249)
begin
builder.computer
rescue Exception => e
puts e.message
end
```
在上面的代码中,我们在`builder = ComputerBuilder.new`中创建一个计算机生成器,接下来我们在`builder.memory_size(249)`行中故意分配低内存,在`begin` `end`块中,我们尝试从`builder`创建一个`Computer`实例。 使用`builder.computer`并确定会引发 ans 异常,该异常会被`rescue`下的`puts e.message`语句捕获并打印出来。 在输出中,我们将得到以下消息:
```rb
Not enough memory.
```
我们以类似的方式尝试构建一台具有五个驱动器的计算机,即 2 个 CD,2 个 DVD 和 1 个硬盘。 在`ComputerBuilder`类中,我们将驱动器的最大数量限制为 4,因此下面的代码段将引发错误:
```rb
# computer must have at most 4 drives
builder = ComputerBuilder.new
builder.add_cd
builder.add_dvd
builder.add_hard_disk(1000)
builder.add_cd
builder.add_dvd
begin
builder.computer
rescue Exception => e
puts e.message
end
```
捕获并打印了此错误,因此我们得到以下输出:
```rb
Too many drives.
```
### 35.1。 行使
你现在了解了构建器模式。 如果你想进一步探索,请看下面的代码
```rb
# use magic method to rapidly build a computer
puts 'Computer built with magic method builder'
builder = ComputerBuilder.new
builder.add_cd_and_dvd_and_harddisk_and_turbo
computer = builder.computer
puts "CPU: #{computer.motherboard.cpu.class}"
computer.drives.each { |drive| puts "Drive: #{drive.type}" }
```
该代码产生以下输出
```rb
Computer built with magic method builder
CPU: TurboCPU
Drive: cd
Drive: dvd
Drive: hard_disk
```
现在,在`ComputerBuilder`类中查看`method_missing`方法,并尝试解释`builder.add_cd_and_dvd_and_harddisk_and_turbo`语句的工作方式。
- 前言
- 红宝石
- 先决条件
- 1.安装 Ruby
- 2.在线资源
- 3.入门
- 4.比较与逻辑
- 5.循环
- 6.数组
- 7.哈希和符号
- 8.范围
- 9.功能
- 10.可变范围
- 11.类&对象
- 12.安全导航
- 13.打破大型程序
- 14.结构和 OpenStruct
- 15. Rdoc
- 16. Ruby 样式指南
- 17.模块和混入
- 18.日期和时间
- 19.文件
- 20. Proc,Lambda 和块
- 21.多线程
- 22.异常处理
- 23.正则表达式
- 24.宝石
- 25.元编程
- 26.基准
- 27.测试驱动开发
- 28.观察者模式
- 29.模板模式
- 30.工厂模式
- 31.装饰图案
- 32.适配器模式
- 33.单例模式
- 34.复合模式
- 35.建造者模式
- 36.策略模式
- 赞助商
- 捐
- 人们怎么说
- 版权
- 取得这本书