如何在Ruby中实现查找类?

时间:2014-10-12 11:35:37

标签: ruby design-patterns class-constants

我有一个不可变值对象列表。 lookup类提供了迭代和查询数据的方法:

class Banker
  Bank = Struct.new(:name, :bic, :codes)

  attr_reader :banks
  def initialize
    @banks = [
      Bank.new('Citibank',    '1234567', ['1', '2']),
      Bank.new('Wells Fargo', '7654321', ['4']), # etc.
    ]
  end

  def find_by_bic(bic)
    banks.each do |bank|
      return bank if bank.bic == bic
    end
  end
end
每次使用@banks时都会初始化

Banker。有哪些选项可以缓存@banks,以便在Banker的不同实例中重复使用?

2 个答案:

答案 0 :(得分:4)

我不认为Struct在这里买了什么。这样做怎么样?

<强>代码

class Banker
  @all_banks = {}

  class << self
    attr_reader :all_banks
  end

  attr_reader :banks

  def initialize(banks)
    @banks = banks.keys
    banks.each { |k,v| self.class.all_banks[k] = v }
  end

  def find_by_bic(bic)
    return nil unless @banks.include?(bic)
    self.class.all_banks[bic]
  end
end

需要self中的self.class来区分self的类与关键字class

示例

b1 = Banker.new({ '1234567' => { name: 'Citibank', codes: ["1", "2"] },
                  '7654321' => { name: 'Wells Fargo', codes: ['4'] } })
b1.banks
  #=> ["1234567", "7654321"]
Banker.all_banks
  #=> {"1234567"=>{:name=>"Citibank", :codes=>["1", "2"]},
  #    "7654321"=>{:name=>"Wells Fargo", :codes=>["4"]}}
b1.find_by_bic '7654321'
  #=> {:name=>"Wells Fargo", :codes=>["4"]}
b1.find_by_bic '1234567'
  #=> {:name=>"Citibank", :codes=>["1", "2"]}
b1.find_by_bic '0000000'
  #=> nil

b2 = Banker.new({ '6523155' => { name: 'Bank of America', codes: ["3"] },
                  '1234567' => { name: 'Citibank', codes: ["1", "2"] } })
b2.banks
  #=> ["6523155", "1234567"]
Banker.all_banks
  #=> {"1234567"=>{:name=>"Citibank", :codes=>["1", "2"]},
  #    "7654321"=>{:name=>"Wells Fargo", :codes=>["4"]},
  #    "6523155"=>{:name=>"Bank of America", :codes=>["3"]}}
b2.find_by_bic '6523155'
  #=> {:name=>"Bank of America", :codes=>["3"]}
b2.find_by_bic '1234567'
  #=> {:name=>"Citibank", :codes=>["1", "2"]}
b2.find_by_bic '7654321'
  #=> nil

<强>替代

如果您愿意,可以改为添加类方法:

def self.new(banks)
  banks.each { |k,v| all_banks[k] = v }
  super
 end

并删除initialize中的第一行。

或者,如果您有所有银行的完整列表,您可以改为all_banks为常数:

ALL_BANKS = {"1234567"=>{:name=>"Citibank", :codes=>["1", "2"]},
             "7654321"=>{:name=>"Wells Fargo", :codes=>["4"]},
             "6523155"=>{:name=>"Bank of America", :codes=>["3"]}}

def find_by_bic(bic)
  return nil unless @banks.include?(bic)
  ALL_BANKS[bic]
end

并将initialize更改为:

def initialize(bics)
  @banks = bics
end

其中bicsbic值的数组。

答案 1 :(得分:3)

要在实例之间共享不可变数据,可以使用冻结类变量:@@banks ||= [...].freeze