2011-08-02 141 views
1

概述红宝石设计问题

我写一个使用数据从MySQL查询创建图表URL的Ruby程序。最近出现了一个新的要求,我们可能需要在未来创建带分组条形图的图形。因此,我可以有任意数量的数据而不是有一组数据。现在,我的BarChart对象的构造函数只需要一个单一的数据数组,而我正在寻找类似于Ruby的方法来允许多个数据数组。

电流构建

#constructor 
    #title   The title of the graph 
    #data   The data that will go in the bar chart 
    #labels   The labels that match the data 
    #x_axis_label The label for the x axis 
    #y_axis_label The label for the y axis 
    def initialize(title, data, labels, x_axis_label, y_axis_label) 
     @title, @data1, @labels, @x_axis_label, @y_axis_label = 
      title, data, labels, x_axis_label, y_axis_label 

     super(@title, @@type, @@size) 
     @url = to_url() 
    end 

我尝试

我最初的想法是使用变参。

#constructor 
    #title   The title of the graph 
    #data   The data that will go in the bar chart 
    #labels   The labels that match the data 
    #x_axis_label The label for the x axis 
    #y_axis_label The label for the y axis 
    def initialize(title, *data, labels, x_axis_label, y_axis_label) 
     ..... 
    end 

这是个不错的点子吗?还是有更好的方法去解决它?

谢谢

回答

7

就个人而言,当你有这么多参数时,我会使用选项散列。

def initialize(options = {}) 
    options = { default options here, if applicable }.merge(options) 
    ... 
end 

所以,你可以构造你的类是这样的:

MyClass.new(:title => "Awesome Graph", :data => [[1,2,3], [4,5,6]], ...) 

我发现这种方法使你的方法调用更可读,所以你不会有一个构造函数调用它有很长的序列做数字和字符串参数的含义可能难以确定。这也给你一种自然的方式来添加任意数量的可选参数和默认值。

+0

合并!您用默认值覆盖参数。您可以通过以下方式对其进行测试: p({:a => 1} .merge!({:a => 2})) – knut

+0

哎呀。我打算使用ActiveSupport中的'reverse_merge!'(如果不使用它,很容易实现)。但我会解决它。 –

1

编辑:添加红宝石版本依赖

这是一个不错的想法,但遗憾的是它不会在1.8.7工作。

1.8.7。他们任意的参数exploder(*data)只能在参数列表的末尾工作。而在1.9.2中只有在没有可选参数的情况下才有效。

所以更多的东西红宝石符合这样可能会奏效,

def initialize(title, labels, x_axis_label, y_axis_label, *data) 
    ..... 
end 

但是,为什么不直接将数据保存它在哪里,做一些鸭子类型看实际上有多少数据存储在数组中。该方法的签名不会改变,但电话会略微,

Object.new(title, [data1, data2, data3], labels, ...) 
+0

嗯,我刚刚读了鸭子打字的维基百科文章,即时消息不知道这是我在找什么。所有的数据是相同的类型,而不是只有1个数据数组我有6个例子。所以我试图使用'* data'而不是'data1,data2,data3,data4,data5 ....'感谢您的评论,我不知道鸭子打字是什么:) –

+0

这不是真正。 splat参数后面没有* optional *参数,但强制的参数非常好。语法基本上是:0个或多个强制性参数,后跟0个或多个可选参数,后跟0或1个splat参数,再跟随0个或多个强制性参数。参数首先从左边绑定到所有左边的强制参数,然后从右边到所有正确的强制参数;任何剩余的参数从可选参数的左边到右边被绑定,其余的被绑定到splat参数。 ... –

+0

...如果还有参数,或者有未绑定的参数,那就是'ArgumentError'。 –

1

像杰里米我使用一个选项散列。

另外我定义了默认和所需的键。 根据我的要求我记录丢失/额外的键或我引发异常。 以下我的Testexample代码只是在stdout上写入一条消息。

class X 
    DEFAULTS = { 
    p1: :default1, 
    p2: :default2 
    } 
    OBLIGATORY_PARAMETERS = [:p1] 
#Parameters: 
# p1 
# p2 
    def initialize(options = {}) 
    (OBLIGATORY_PARAMETERS - options.keys).each{|key| 
     puts "Missing key #{key}" 
    } 
    (options.keys - OBLIGATORY_PARAMETERS - DEFAULTS.keys).each{|key| 
     puts "Undefined key #{key}" 
    } 
    @options = DEFAULTS.merge(options) 
    end 
end 

#Ok 
X.new(p1: 1)#<X:0xc8c760 @options={:p1=>1, :p2=>:default2}> 
#Missing key warnings 
X.new() ##<X:0xc8c960 @options={:p1=>:default1, :p2=>:default2}> 
X.new(p2: 2)#<X:0xc8c5c0 @options={:p1=>:default1, :p2=>2}> 
#Undefined parameter -> Exception 
p X.new(p3: 3)#<X:0xc8c5c0 @options={:p1=>:default1, :p2=>2}>