Рубиновый вопрос дизайна - PullRequest
1 голос
/ 02 августа 2011

Обзор

Я пишу Ruby-программу, которая использует данные из запросов MySQL для создания URL-адресов диаграмм. Недавно появилось новое требование, в котором нам, возможно, понадобится создать графики с сгруппированными столбцами в будущем. Таким образом, вместо одного набора данных, я мог бы иметь любое количество наборов. Прямо сейчас конструктор для моего объекта 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

Моя попытка

Моей первоначальной мыслью было использование var args.

    #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

Это приличная идея? или есть лучший способ сделать это?

Спасибо

Ответы [ 3 ]

7 голосов
/ 02 августа 2011

Лично, когда у вас столько аргументов, я бы использовал хеш опций.

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

, чтобы вы могли построить свой класс следующим образом:

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

Я нашелподход делает ваши вызовы методов намного более читабельными, поэтому у вас нет вызова конструктора, который имеет длинную последовательность числовых и строковых аргументов, значение которых может быть трудно определить.Это также дает вам естественный способ добавить произвольное количество необязательных параметров со значениями по умолчанию.

1 голос
/ 03 августа 2011

Как и Джереми, я использую опциональный хеш.

Кроме того, я определяю значения по умолчанию и необходимые ключи. В зависимости от моих требований, я регистрирую отсутствующие / дополнительные ключи или выдвигаю исключение. Мой код Testexample ниже просто пишет сообщение на стандартный вывод.

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}>
1 голос
/ 02 августа 2011

РЕДАКТИРОВАТЬ: добавлены зависимости версии ruby ​​

Это хорошая идея, но, к сожалению, она не будет работать в 1.8.7.

В 1.8.7. произвольный аргумент exploder (*data) работает только в конце списка аргументов. А в 1.9.2 работает только если нет дополнительных параметров.

Так что что-то более совместимое с ruby ​​может сработать,

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

Однако, почему бы просто не сохранить данные там, где они есть, и выполнить некоторую утку, чтобы узнать, сколько данных фактически хранится в массиве. Сигнатура метода не изменится, но вызов слегка изменится на

Object.new(title, [data1, data2, data3], labels, ... )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...