ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 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 &lt; CPU # basic cpu stuff... end class TurboCPU &lt; 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 &lt;&lt; Drive.new(:cd, 760, writable) end def add_dvd(writable = false) @computer.drives &lt;&lt; Drive.new(:dvd, 4700, writable) end def add_hard_disk(size_in_mb) @computer.drives &lt;&lt; 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 &#124;word&#124; 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 &lt; 250 raise 'Too many drives.' if @computer.drives.size &gt; 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 &lt;&lt; builder.computer.clone } computers.each { &#124;computer&#124; puts computer } # computer must have at least 250 MB of memory builder = ComputerBuilder.new builder.memory_size(249) begin builder.computer rescue Exception =&gt; 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 =&gt; 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 { &#124;drive&#124; 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`,我们可以克隆 &lt;sup class="footnote"&gt;[ [67](#_footnotedef_67 "View footnote.") ]&lt;/sup&gt; 以创建任意数量的计算机。 在下面的代码中,我们创建 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`语句的工作方式。