2015-06-24 3 views
3

В настоящее время я пишу программу для банковской системы администрирования с использованием Ruby. Одна из возможностей этой системы заключается в том, что она может создать новую учетную запись, учетные записи могут быть одного из шести типов.Альтернатива Ruby Case statement

У меня есть следующий метод, в моем контроллере для удовлетворения этой функции:

def create_account(type, holder) 
    case type 
    when :current then CurrentAccount.new(holder, @account_number) 
    when :savings then SavingsAccount.new(holder, @account_number) 
    when :business then BusinessAccount.new(holder, @account_number) 
    when :ir  then IRAccount.new(holder, @account_number) 
    when :smb  then SMBAccount.new(holder, @account_number) 
    when :student then StudentAccount.new(holder, @account_number) 
    end 
end 

Каждые из этих счетов наследует от базовой учетной записи и, в конечном счете содержать отдельные атрибуты, например, Процентная ставка, овердрафт и т. Д.

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

Любые предложения приветствуются ...

ответ

6

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

Вы можете сделать то, что у вас есть, путем определения отображения между символом type и классом. Таким образом, вы могли бы сделать это в рамках create_account:

ACCOUNT_CLASS_FOR = Hash[ 
    current: CurrentAccount, 
    savings: SavingsAccount, 
    business: BusinessAccount, 
    ir:  IRAccount, 
    smb:  SMBAccount, 
    student: StudentAccount 
] 

def create_account(type, holder) 
    if account_class = ACCOUNT_CLASS_FOR[ type ] 
    account_class.new(holder, @account_number) 
    else 
    raise "Bad account type #{type}" 
    end 
end 

Это менее повторил код, и делает отображение между именами символов и соответствующими классами Ruby, более явными. Если вам нужно применить или протестировать конверсию в другом месте, вы можете сделать константу доступной в другой области, не повторяя себя.

Вы можете сделать это еще более чистым, если каждый класс узнает собственную метку, например.

class CurrentAccount 
    def self.label 
    :current 
    end 
end 

Тогда вы могли бы иметь что-то вроде этого:

ALLOWED_ACCOUNT_CLASSES = [CurrentAccount,SavingsAccount,BusinessAccount, # etc. 

ACCOUNT_CLASS_FOR = Hash[ 
    ALLOWED_ACCOUNT_CLASSES.map { |klass| [klass.label, klass] } 
] 

Примечание это довольно обычная практика, чтобы использовать неправильно написанное klass переменной здесь, чтобы избежать столкновения с class ключевого слова Руби, но вы могли бы просто использовать account_class

3

Вот еще один способ, но вам нужно будет тип быть соответствующим образом назван с классом (то есть: л ->:. i_r)

def create_account(type, holder) 
    Object.const_get(type.to_s.camelize + "Account").new(holder, @account_number) 
end 

Даже если это один короче, мне нравится Neil ответ, потому что это выглядит безопаснее

+0

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