将许多变量添加到 class 的 Rubyish 方式
Rubyish way of adding many variables to a class
我一直在开发一款需要模拟一长串国家/地区的游戏(如果有的话,更像是网络玩具),我已经设法让它运行,但我情不自禁感觉我的解决方案既不是 Rubyish 也不优雅。
代码看起来有点像这样:
class Countries
include Singleton
def get(tag)
return eval "@#{tag}"
end
def initialize
@array = []
@afghanistan = Country.new("Afghanistan", [:authoritarian, :reactionary, :sunni, :capitalist, :militarist, :southern_asia, :unstable])
@afghanistan.gdp = 20444
@afghanistan.population = 26023
@array << :afghanistan
@albania = Country.new("Albania", [:hybrid, :conservative, :sunni, :capitalist, :pacifist, :southern_europe])
@albania.gdp = 13276
@albania.population = 2893
@array << :albania
#and so on and so forth
end
attr_accessor :array
end
countries = Countries.instance
puts countries.get("usa").name
puts
for i in 0..(countries.array.size-1)
puts countries.get(countries.array[i]).name
end
我得到了预期的输出
United States
Afghanistan
Albania
Algeria
...
但理想情况下,优雅的解决方案不需要 .get(),这看起来确实不像 Ruby 那样解决此问题的方法。有更好的做法吗?
我主要从 Stack Overflow、Ruby 文档和测试中学到了一点点知识,所以我很可能在此过程中违反了很多最佳实践。 Country class 的初始化程序接受一个字符串作为名称和一个要添加的标签数组,而其他属性则打算在单独的行中添加。
我会将国家/地区的详细信息存储在文件(e.q。countries.yml 或 csv 文件)或数据库中:
# in countries.yml
afganistan:
name: Afganistan
tags:
- authoritarian
- reactionary
- sunni
- capitalist
- militarist
- southern_asia
- unstable
gdp: 20444
population: 26023
albania:
name: Albania
tags:
...
...
然后你的class简化为:
require 'yaml'
class Countries
include Singleton
def get(country)
@countries[country]
end
def initialize
@countries = {}
YAML.load_file('countries.yml').each do |country_key, options|
country = Country.new(options['name'], options['tags'])
country.gdp = options['gdp']
country.population = options['population']
@countries[country_key] = country
end
@countries.keys # just to keep the interface compatible with your example
end
end
您可以通过数百种方法来 DRY 代码,但您的错误本质上是没有使用 hash data stucture(或建议的外部文件)。
这就是我的做法,我做了一些假设,希望对您有所帮助!
# I'll assume that Country is an actual class with a purpose, and not a simple
# structure.
Country = Struct.new(:name, :tags, :gdp, :population)
# list of all the countries
COUNTRIES_TABLE = [
["Afghanistan", [:authoritarian, :reactionary], 20444, 26023],
["Albania", [:hybrid, :conservative], 13276, 2893]
# etc..
]
COUNTRIES = COUNTRIES_TABLE.map { |e| Country.new(*e) }
# we could have directly defined the hash instead of a table, but this keeps
# everything more DRY
COUNTRIES_HASH = COUNTRIES.map {|e| [e.name, e]}.to_h
puts COUNTRIES_HASH["Albania"].name
COUNTRIES_HASH.map do |k,v|
puts v.name
end
我一直在开发一款需要模拟一长串国家/地区的游戏(如果有的话,更像是网络玩具),我已经设法让它运行,但我情不自禁感觉我的解决方案既不是 Rubyish 也不优雅。
代码看起来有点像这样:
class Countries
include Singleton
def get(tag)
return eval "@#{tag}"
end
def initialize
@array = []
@afghanistan = Country.new("Afghanistan", [:authoritarian, :reactionary, :sunni, :capitalist, :militarist, :southern_asia, :unstable])
@afghanistan.gdp = 20444
@afghanistan.population = 26023
@array << :afghanistan
@albania = Country.new("Albania", [:hybrid, :conservative, :sunni, :capitalist, :pacifist, :southern_europe])
@albania.gdp = 13276
@albania.population = 2893
@array << :albania
#and so on and so forth
end
attr_accessor :array
end
countries = Countries.instance
puts countries.get("usa").name
puts
for i in 0..(countries.array.size-1)
puts countries.get(countries.array[i]).name
end
我得到了预期的输出
United States
Afghanistan
Albania
Algeria
...
但理想情况下,优雅的解决方案不需要 .get(),这看起来确实不像 Ruby 那样解决此问题的方法。有更好的做法吗?
我主要从 Stack Overflow、Ruby 文档和测试中学到了一点点知识,所以我很可能在此过程中违反了很多最佳实践。 Country class 的初始化程序接受一个字符串作为名称和一个要添加的标签数组,而其他属性则打算在单独的行中添加。
我会将国家/地区的详细信息存储在文件(e.q。countries.yml 或 csv 文件)或数据库中:
# in countries.yml
afganistan:
name: Afganistan
tags:
- authoritarian
- reactionary
- sunni
- capitalist
- militarist
- southern_asia
- unstable
gdp: 20444
population: 26023
albania:
name: Albania
tags:
...
...
然后你的class简化为:
require 'yaml'
class Countries
include Singleton
def get(country)
@countries[country]
end
def initialize
@countries = {}
YAML.load_file('countries.yml').each do |country_key, options|
country = Country.new(options['name'], options['tags'])
country.gdp = options['gdp']
country.population = options['population']
@countries[country_key] = country
end
@countries.keys # just to keep the interface compatible with your example
end
end
您可以通过数百种方法来 DRY 代码,但您的错误本质上是没有使用 hash data stucture(或建议的外部文件)。
这就是我的做法,我做了一些假设,希望对您有所帮助!
# I'll assume that Country is an actual class with a purpose, and not a simple
# structure.
Country = Struct.new(:name, :tags, :gdp, :population)
# list of all the countries
COUNTRIES_TABLE = [
["Afghanistan", [:authoritarian, :reactionary], 20444, 26023],
["Albania", [:hybrid, :conservative], 13276, 2893]
# etc..
]
COUNTRIES = COUNTRIES_TABLE.map { |e| Country.new(*e) }
# we could have directly defined the hash instead of a table, but this keeps
# everything more DRY
COUNTRIES_HASH = COUNTRIES.map {|e| [e.name, e]}.to_h
puts COUNTRIES_HASH["Albania"].name
COUNTRIES_HASH.map do |k,v|
puts v.name
end