45.md 5.2 KB
Newer Older
W
init  
wizardforcel 已提交
1 2
## 36.策略模式

W
wizardforcel 已提交
3
无论你是否意识到自己是一名出色的战略家。 早上醒来时,你会去喝咖啡,如果没有咖啡粉,你可能会喝杯茶或热巧克力或牛奶。 你开车去上班或上学,如果某条路受阻,则采取另一种方式。 在工作中,你需要考虑向老板呈现的方式,是否使老板心情愉快的方式,以便你可以谈论事实或掩盖事实。 策略无处不在,你只是没有注意到它。 你每次都会根据环境 <sup class="footnote">[ [68](#_footnotedef_68 "View footnote.") ]</sup> 不断采用新策略。
W
init  
wizardforcel 已提交
4 5 6

在计算世界中,如果我们能够根据传递的标志/参数告诉一段代码动态运行不同的算法,则这种编码称为策略模式。 让我们看下面的示例 [strategy_pattern.rb](code/design_patterns/strategy_pattern.rb)

W
wizardforcel 已提交
7
```rb
W
init  
wizardforcel 已提交
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
 ```
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

W
wizardforcel 已提交
55
```rb
W
init  
wizardforcel 已提交
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103

 |

```
# strategy_pattern.rb

module NewsFormatter
  class Text
    def self.format(data)
      seperator = "\n* "
      seperator + data.join(seperator)
    end
  end

  class HTML
    def self.format(data)
      html = []
      html << "<ul>"
      data.each { |datum| html << "<li>#{datum}</li>" }
      html << "</ul>"
      html.join "\n"
    end
  end
end

class NewsGenerator
  def self.generate(data, formatter)
    formatter.format(data)
  end
end

news = [
  "You are reading I Love Ruby.",
  "There is water down below in the oceans.",
  "There is air up above our heads.",
  "Even people in space report their is air up above their heads.",
  "Even bald people have air up above their heads."
]

puts "News As HTML:"
puts "\n"
puts NewsGenerator.generate(news, NewsFormatter::HTML)
puts "\n\n"

puts "News As Text:"
puts "\n"
puts NewsGenerator.generate(news, NewsFormatter::Text)
puts "\n\n"
W
wizardforcel 已提交
104
```rb
W
init  
wizardforcel 已提交
105 106 107 108 109 110 111 112

 | 
```

输入并执行

输出量

W
wizardforcel 已提交
113
```rb
W
init  
wizardforcel 已提交
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
News As HTML:

<ul>
<li>You are reading I Love Ruby.</li>
<li>There is water down below in the oceans.</li>
<li>There is air up above our heads.</li>
<li>Even people in space report their is air up above their heads.</li>
<li>Even bald people have air up above their heads.</li>
</ul>

News As Text:

* You are reading I Love Ruby.
* There is water down below in the oceans.
* There is air up above our heads.
* Even people in space report their is air up above their heads.
* Even bald people have air up above their heads.
```

现在让我们分析代码。 查看以下几行(29-35):

W
wizardforcel 已提交
135
```rb
W
init  
wizardforcel 已提交
136 137 138 139 140 141 142 143 144 145 146 147 148
news = [
  "You are reading I Love Ruby.",
  "There is water down below in the oceans.",
  "There is air up above our heads.",
  "Even people in space report their is air up above their heads.",
  "Even bald people have air up above their heads."
]
```

在这里,我们声明一个名为`news`的数组,并在其中填充新闻项。

然后在第 39 行中,有以下语句`puts NewsGenerator.generate(news, NewsFormatter::HTML)`,其输出如下:

W
wizardforcel 已提交
149
```rb
W
init  
wizardforcel 已提交
150 151 152 153 154 155 156 157 158 159 160 161 162
<ul>
<li>You are reading I Love Ruby.</li>
<li>There is water down below in the oceans.</li>
<li>There is air up above our heads.</li>
<li>Even people in space report their is air up above their heads.</li>
<li>Even bald people have air up above their heads.</li>
</ul>
```

注意,对于`NewsGenerator`类中的`generate`方法,我们提供了两个参数作为输入,第一个是数据,在这种情况下,数据是`news`数组,其中包含新闻列表。 下一个参数是`NewsFormatter::HTML`,这是打印时要遵循的策略。

现在看第 24 行的 generate 方法,它看起来像这样:

W
wizardforcel 已提交
163
```rb
W
init  
wizardforcel 已提交
164 165 166 167 168
def self.generate(data, formatter)
  formatter.format(data)
end
```

W
wizardforcel 已提交
169
在这里,我们将`formatter`作为第二个参数,即本例中的`NewsFormatter::HTML`,并将其传递给`data`作为参数,从而对其调用`format`方法。 因此,程序控制转到第 12 行,该行位于模块`NewsFormatter`内,并进入类`HTML`中的方法`self.format`中,你可以在此处看到代码段
W
init  
wizardforcel 已提交
170

W
wizardforcel 已提交
171
```rb
W
init  
wizardforcel 已提交
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
module NewsFormatter
  ....

  class HTML
    def self.format(data)
      html = []
      html << "<ul>"
      data.each { |datum| html << "<li>#{datum}</li>" }
      html << "</ul>"
      html.join "\n"
    end
  end
end
```

在该函数中,我们神奇地将其转换为 HTML 无序列表 &lt;sup class="footnote"&gt;[ [69](#_footnotedef_69 "View footnote.") ]&lt;/sup&gt; ,然后将其返回。

当我们调用`puts NewsGenerator.generate(news, NewsFormatter::Text)`时,会发生相同的事情,但是由于我们通过了不同的策略`NewsFormatter::Text`,因此这段代码得以执行:

W
wizardforcel 已提交
191
```rb
W
init  
wizardforcel 已提交
192 193 194 195 196 197 198 199 200 201 202 203
module NewsFormatter
  class Text
    def self.format(data)
      seperator = "\n* "
      seperator + data.join(seperator)
    end
  end

  ....
end
```

W
wizardforcel 已提交
204
那就是调用了模块`NewsFormatter`中类`Text`中的函数`self.format`,该函数会产生纯文本输出,如项目符号,因此你将看到以下输出:
W
init  
wizardforcel 已提交
205

W
wizardforcel 已提交
206
```rb
W
init  
wizardforcel 已提交
207 208 209 210 211 212
* You are reading I Love Ruby.
* There is water down below in the oceans.
* There is air up above our heads.
* Even people in space report their is air up above their heads.
* Even bald people have air up above their heads.
```