## 34.复合模式
看看下面的代码 [iling_egg.rb](code/design_patterns/boiling_egg.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
48
49
50
51
52
53
54
55
56
57
58
59
60
```rb
|
```
require_relative "node.rb"
class BuyEggs < Node
attr_accessor :time_in_minutes
def initialize
@time_in_minutes = 15
super "Buy eggs"
end
end
class BoilEggs < Node
attr_accessor :time_in_minutes
def initialize
@time_in_minutes = 10
super "Boil eggs"
end
end
class PeelEggs < Node
attr_accessor :time_in_minutes
def initialize
@time_in_minutes = 3
super "Peel eggs"
end
end
class ServeEggs < Node
attr_accessor :time_in_minutes
def initialize
@time_in_minutes = 2
super "Serve eggs"
end
end
class BoiledEggs < Node
def initialize
super "Boiled eggs"
add_child BuyEggs.new
add_child BoilEggs.new
add_child PeelEggs.new
add_child ServeEggs.new
end
def total_time_in_minutes
total = 0
for child in self.children
total += child.time_in_minutes
end
total
end
end
boiled_eggs = BoiledEggs.new
puts "Time (in minutes) to make boiled eggs is #{boiled_eggs.total_time_in_minutes}."
```rb
|
```
输出量
```rb
Time (in minutes) to make boiled eggs is 30.
```
在复合模式中,我们将一个类分为许多类。 假设需要以面向对象的方式表示煮鸡蛋,我们可以将`BoiledEggs`编写为如下所示的类。
```rb
class BoiledEggs < Node
def initialize
super "Boiled eggs"
add_child BuyEggs.new
add_child BoilEggs.new
add_child PeelEggs.new
add_child ServeEggs.new
end
def total_time_in_minutes
total = 0
for child in self.children
total += child.time_in_minutes
end
total
end
end
```
`BoiledEggs`继承了一个名为`Node`的类,该类有助于构建树结构。 稍后再讨论`Node`类。 现在让我们专注于复合模式。 如你在`initialize`方法中所见,在该类中`BoiledEggs`被划分为许多类,即`BuyEggs`至`ServeEggs`,并且它们被作为子节点添加到`BoiledEggs`中。
如果你可以看到类`BuyEggs`如下所示:
```rb
class BuyEggs < Node
attr_accessor :time_in_minutes
def initialize
@time_in_minutes = 15
super "Buy eggs"
end
end
```
如果看到类`ServeEggs`,则如下所示:
```rb
class ServeEggs < Node
attr_accessor :time_in_minutes
def initialize
@time_in_minutes = 2
super "Serve eggs"
end
end
```
实际上,它看起来与`BuyEggs`非常相似,因此可以按照相似的方式处理这些类。 因此`BoiledEggs`就像是由不同对象组成的,可以用相似的方式对其进行处理。
现在`BoiledEggs`中的每个类都具有`time_in_minutes`属性。 因此,如果我们需要以分钟为单位计算制作煮鸡蛋的总时间,我们要做的就是编写一个函数`total_time_in_minutes`,如下所示
```rb
class BoiledEggs < Node
...
def total_time_in_minutes
total = 0
for child in self.children
total += child.time_in_minutes
end
total
end
end
```
因此,复合模式可以用于存在复杂对象的地方,可以将其功能分解为较小的对象,可以以非常相似的方式处理这些较小的对象,并将这些较小的对象放置在树状结构中。
谈论树结构,我们建立了一个名为`Node`的类,可以在文件 [node.rb](code/design_patterns/node.rb) 中找到该类。 你可以在下面看到它。
```rb
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
```rb
|
```
class Node
attr_accessor :name, :parent, :children
def initialize name = "node"
@name = name
@parent = nil
@children = []
end
def to_s
"<Node: #{@name}, id: #{self.object_id}>"
end
def add_child node
children << node
node.parent = self
end
end
```rb
|
```
它具有一个称为`add_child`的功能,通过它我们可以添加子元素。 你可以使用`parent`功能获取节点的父节点。 要查看此节点类的工作方式,请看下面的代码 [Composite.rb](code/design_patterns/composite.rb) :
```rb
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
```rb
|
```
# composite.rb
require_relative "node.rb"
n1 = Node.new "n1"
n2 = Node.new "n2"
n3 = Node.new "n3"
n1.add_child n2
n1.add_child n3
puts "children of #{n1} are:"
for node in n1.children
puts node
end
puts
puts "Parent of #{n3} is #{n3.parent}"
```rb
|
```
Output
```rb
children of <Node: n1, id: 47253445808700> are:
<Node: n2, id: 47253445808560>
<Node: n3, id: 47253445808360>
Parent of <Node: n3, id: 47253445808360> is <Node: n1, id: 47253445808700>
```
- 前言
- 红宝石
- 先决条件
- 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.策略模式
- 赞助商
- 捐
- 人们怎么说
- 版权
- 取得这本书