我有一个进行计算的课程。大多数情况下,它在代码中用于输出单个值:
使用:value = Calculator.new(1234).output
这是类定义的一个例子:
class Calculator
def initialize(parameter_1)
@parameter_1 = parameter_1
end
def output
op_1_result = operation_1(@parameter_1)
op_2_result = operation_2(op_1_result)
operation_3(op_2_result)
end
def operation_1(param)
...
end
但有时用户必须打印计算报告,显示计算中的许多变量。
我实现的第一个解决方案是在初始化时传递一个参数,告诉类它应该为报告保存一些内部变量,如下所示:
class Calculator
attr_reader :report
def initialize(parameter_1, reporting=false)
@parameter_1 = parameter_1
@reporting = reporting
@report = {}
end
def output
op_1_result = operation_1(@parameter_1)
@report[:op_1_result] = op_1_result if @reporting
op_2_result = operation_2(op_1_result)
@report[:op_2_result] = op_2_result if @reporting
operation_3(op_2_result)
end
def operation_1(param)
...
end
然后,当我想得到那些中间变量时,我会:
calculator = Calculator.new(1234, true) # reporting activated
report = calculator.report
report[:op_1_result] # one of the intermediate variables of the calculation
这是否打破了单一责任原则,因为班级现在正在计算价值并同时报告?
有没有更好的方法来实现这一点,我可以在需要时快速计算输出结果的设计模式,并在没有所有ifs的情况下显示所需的报告?
对此有任何启发和意见将非常感谢!
Obs(另一个讨论):我已经读过,只是输出一个值的更实用的方法将是一件好事。但这让我想知道如何在需要时显示那些内部中间值。更多功能程序员如何做到这一点......?
答案 0 :(得分:2)
我猜“构建器模式”是合适的,“报告板”应该从外部注入。
class Calculator
def initialize(*parameters)
@parameters = parameters
end
def report_to(report_pad)
@report_pad = report_pad
self
end
def output()
ret = @parameters[0].to_i + @parameters[1].to_i
report('Did p0 + p1')
ret
end
private
def report(message)
@report_pad << "\n".prepend(message) if @report_pad.respond_to? '<<'
end
end
####
reports = ""
result = Calculator
.new(1, 2)
.report_to(reports)
.output()
puts result, reports
答案 1 :(得分:1)
为什么不让所有中间结果成为公共方法并将结果链接到最终输出中?
也许是这样的:
class Calculator
def initialize(parameter)
@parameter = parameter
end
def output
op_3_result
end
def op_1_result
@op_1_result ||= operation_1(parameter)
end
def op_2_result
@op_2_result ||= operation2(op_1_result)
end
def op_3_result
@op_3_result ||= operation3(op_2_result)
end
private
def operation1(arg)
# ...
end
def operation2(arg)
# ...
end
def operation3(arg)
# ...
end
attr_reader :parameter
end
这将允许您在同一个实例上调用所需的任何内容:
calculator = Calculator.new(1234)
calculator.output #=> the final result
calculator.op_2_result #=> the intermediate result of step 2
答案 2 :(得分:1)
您可以使用不同的模式,.ag-header-select-all
是自己的类,并允许它在关闭报告时通过。这是一个简单的例子:
Report
然后你可以这样使用
class Calculator
attr_reader :report
def initialize(parameter_1, reporting=false)
@parameter_1 = parameter_1
@report = Report.new(reporting)
end
def output
op1 = operation_1(report.capture(:param1,@parameter_1))
report.capture(:op1,op1)
op2 = report.capture(:op2) { operation_2(op1) }
operation_3(op2)
end
def operation_1(param);
param + 7
end
def operation_2(param);
param - 3
end
def operation_3(param);
param * 2
end
end
class Report
attr_reader :reporting, :reportables
def initialize(reporting)
@reporting = reporting
@reportables = {}
end
def capture(key, val=nil,&block)
warn "Block supercedes value" if val && block_given?
result = block_given? ? block.call : val
@reportables[key] = result if reporting
result
end
def [](key)
return 'No Reporting' unless reporting
@reportables[key]
end
end
这样,每个步骤都可以使用一个块来处理应该捕获结果的更复杂的项目,或者只是在你选择的时候传递一个值,并且像c = Calculator.new(12)
c.output
#=> 32
c.report[:op1]
#=> "No Reporting"
c = Calculator.new(12, true)
c.output
#=> 32
c.report[:op1]
#=> 19
c.report[:param1]
#=> 12
这样的中间步骤(在这种情况下)不需要“捕获“只能流过。
如果报告已关闭,则所有内容都会流过,并且会忽略捕获。
你的operation_3
方法看起来也像这样(根本没有中间本地人,虽然它确实会损害可读性)
#output