在一篇关于unconditional programming的博文中,Michael Feathers展示了如何将限制if
语句用作降低代码复杂性的工具。
他用一个具体的例子来说明他的观点。现在,我一直在考虑其他具体示例,这些示例可以帮助我更多地了解无条件/ if
少/ for
编程。
例如,使用OptionParser我创建了一个cat克隆,如果设置了--upcase
开关,该克隆会使流整齐:
#!/usr/bin/env ruby
require 'optparse'
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: cat [options] [file ...]"
opts.on("-u", "--upcase", "Upcase stream") do
options[:upcase] = true
end
end.parse!
if options[:upcase]
puts ARGF.read.upcase
else
puts ARGF.read
end
如果没有if..else
阻止,我将如何处理该切换?
也对其他说明性具体示例的链接感兴趣。
答案 0 :(得分:3)
试试这个,
#!/usr/bin/env ruby
require 'optparse'
options = { :transform => :itself }
OptionParser.new do |opts|
opts.banner = "Usage: cat [options] [file ...]"
opts.on("-u", "--upcase", "Upcase stream") do
options[:transform] = :upcase
end
# add more options for downcase, reverse, etc ...
end.parse!
puts ARGF.read.send(options[:transform])
这很有效,我真的很惊讶它的效果如何。
发生了什么变化?
:transform
:itself
:upcase
send
尽管如此,并非所有if
语句都可以改进。我猜想无条件编程的想法是更喜欢有意义的默认值的组合,就像我上面所做的那样,并且只要看起来合理但不是不惜一切代价,意图揭示功能。
以下是意图揭示功能的一些例子,
max
min
Hash#fetch
Enumerable#detect
Enumerable#select
Enumerable#chunk
Enumerable#drop_while
Enumerable#slice_when
Enumerable#take_while
另一种相关做法是for
少编程。
如果你想练习无条件和for
编程,最好寻找处理数组和字符串的例子,并利用许多" functional" Ruby的可枚举模块中的方法。
以下是没有for
和if
,
str = 'This is an example to be aligned to both margins'
words = str.split
width, remainder = (50 - words.map(&:length).inject(:+)).divmod(words.length - 1)
words.take(words.length - 1).each { |each| width.times { each << 32 }}
words.take(words.length - 1).shuffle.take(remainder).each { |each| each << 32 }
p words.join
# => "This is an example to be aligned to both margins"
答案 1 :(得分:1)
消除条件是降低复杂性的工具,而不是最终目标。 I explained that better in my other answer。在这种情况下,条件必须存在,因为是否设置了options[:upcase]
是逻辑的一部分。但你至少可以消除重复。
因为else子句与if子句相同但只是添加了一个步骤,所以你可以通过无条件地执行公共位来删除重复并使代码成为线性,然后有条件地执行额外的操作。
data = ARGF.read;
data.upcase! if options[:upcase];