多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## 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 &lt; Node attr_accessor :time_in_minutes def initialize @time_in_minutes = 15 super "Buy eggs" end end class BoilEggs &lt; Node attr_accessor :time_in_minutes def initialize @time_in_minutes = 10 super "Boil eggs" end end class PeelEggs &lt; Node attr_accessor :time_in_minutes def initialize @time_in_minutes = 3 super "Peel eggs" end end class ServeEggs &lt; Node attr_accessor :time_in_minutes def initialize @time_in_minutes = 2 super "Serve eggs" end end class BoiledEggs &lt; 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 "&lt;Node: #{@name}, id: #{self.object_id}&gt;" end def add_child node children &lt;&lt; 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> ```