2014-10-12 4 views
3

У меня есть список объектов неизменяемых значений. Класс поиска предоставляет способы перебирать и запрашивать эти данные:Как реализовать класс поиска в Ruby?

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?

+0

Я не понимаю причину нисходящего потока. Я думаю, что вопрос и проблема хорошо объяснены. Пожалуйста, уточните, чего не хватает! – randomguy

+0

Вопрос для меня довольно ясен, но его возможный опросник опроса самого себя был немного широк (я бы не согласился, если бы это было так). Или что название не совсем совпадает с тем, что вы на самом деле спрашиваете (не совсем лидирующей причиной imo). –

ответ

3

Для обмена неизменных данных между экземплярами вы можете использовать переменные замороженный класс: @@banks ||= [...].freeze

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 

где bics является массивом bic значений.