Ruby Case语句的替代方案

时间:2015-06-24 18:30:03

标签: ruby switch-statement

我目前正在使用Ruby为银行管理系统编写程序。该系统的一个功能是它可以创建一个新帐户,帐户可以是六种类型之一。

我的控制器中有以下方法可以满足此功能:

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

这些帐户中的每一个都从一个基本帐户继承,最终将包含各个属性,例如利率,透支等

虽然这是功能性的并且提供了所需的结果,但感觉有点冗长。但是我想不出任何明显的重构方法。

欢迎任何建议......

2 个答案:

答案 0 :(得分: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变量以避免与Ruby的class关键字发生冲突是很常见的做法,但您也可以使用account_class

答案 1 :(得分:3)

这是另一种方式,但你需要相应的类命名类型(即:ir - >:i_r)

<?PHP

// example data. The key values will become part of the jscript object //
$data = ["area1" => "blahblahblah", "area2" => "<i>Something</i>"];

// need this for it to be recognized by jQuery as JSON
header('Content-Type: application/json'); 

echo json_encode($data);

即使这个更短,我也喜欢Neil回答,因为它看起来更安全