当前位置:  开发笔记 > 后端 > 正文

在Ruby中动态创建类

如何解决《在Ruby中动态创建类》经验,为你挑选了2个好方法。

我有一个类应该看起来像这样:

class Family_Type1
    @people = Array.new(3)
    @people[0] = Policeman.new('Peter', 0)
    @people[1] = Accountant.new('Paul', 0)
    @people[2] = Policeman.new('Mary', 0)

    def initialize(*ages)
        for i in 0 ... @people.length
            @people[i].age = ages[i]
        end
    end
end

我希望能够在运行时定义一组类似于这一类的类(在启动时定义它们一次),其中数组的大小和分配给每个参数的类型是在运行时从外部规范文件定义的.

我有点使用evals工作,但这真的很难看.有更好的方法吗?



1> Chirantan..:

据我所知,你需要元编程.以下是使用初始化实例变量的初始化方法动态(动态)创建类的代码片段 -

class_name = 'foo'.capitalize
klass = Object.const_set(class_name,Class.new)

names = ['instance1', 'instance2'] # Array of instance vars

klass.class_eval do
  attr_accessor *names

  define_method(:initialize) do |*values|
    names.each_with_index do |name,i|
      instance_variable_set("@"+name, values[i])
    end
  end
  # more...
end

希望你能调整它以满足你的要求.



2> rampion..:

首先,您的示例代码不适合您的部分原因是您有两个不同的@people变量 - 一个是实例变量,另一个是类实例变量.

class Example
  # we're in the context of the Example class, so 
  # instance variables used here belong to the actual class object,
  # not instances of that class
  self.class #=> Class
  self == Example #=> true
  @iv = "I'm a class instance variable"

  def initialize
    # within instance methods, we're in the context
    # of an _instance_ of the Example class, so
    # instance variables used here belong to that instance.
    self.class #=> Example
    self == Example #=> false
    @iv = "I'm an instance variable"
  end
  def iv
    # another instance method uses the context of the instance
    @iv #=> "I'm an instance variable"
  end
  def self.iv
    # a class method, uses the context of the class
    @iv #=> "I'm a class instance variable"
  end
end

如果要在类中创建一次变量以在该类的实例方法中使用,请使用constantsclass variables.

class Example
  # ruby constants start with a capital letter.  Ruby prints warnings if you
  # try to assign a different object to an already-defined constant
  CONSTANT_VARIABLE = "i'm a constant"
  # though it's legit to modify the current object
  CONSTANT_VARIABLE.capitalize!
  CONSTANT_VARIABLE #=> "I'm a constant"

  # class variables start with a @@
  @@class_variable = "I'm a class variable"

  def c_and_c
    [ @@class_variable, CONSTANT_VARIABLE ] #=> [ "I'm a class variable", "I'm a constant" ]
  end
end

即便如此,在您的代码的上下文中,您可能不希望所有的Family_Type1实例都引用相同的警察和会计师吗?或者你呢?

如果我们切换到使用类变量:

class Family_Type1
    # since we're initializing @@people one time, that means
    # all the Family_Type1 objects will share the same people
    @@people = [ Policeman.new('Peter', 0), Accountant.new('Paul', 0), Policeman.new('Mary', 0) ]

    def initialize(*ages)
        @@people.zip(ages).each { |person, age| person.age = age }
    end
    # just an accessor method
    def [](person_index)
      @@people[person_index]
    end
end
fam = Family_Type1.new( 12, 13, 14 )
fam[0].age == 12 #=> true
# this can lead to unexpected side-effects 
fam2 = Family_Type1.new( 31, 32, 29 )
fam[0].age == 12 #=> false
fam2[0].age == 31 #=> true
fam[0].age == 31 #=> true

正如Chirantan所说,运行时初始化可以通过元编程完成,但是如果你只是初始化几个类,并且你知道他们的名字是什么,你也可以通过使用从文件中读取的任何内容来完成:

PARAMS = File.read('params.csv').split("\n").map { |line| line.split(',') }
make_people = proc do |klasses, params|
  klasses.zip(params).map { |klass,name| klass.new(name, 0) }
end
class Example0
  @@people = make_people([ Fireman, Accountant, Fireman ], PARAMS[0])
end
class Example1
  @@people = make_people([ Butcher, Baker, Candlestickmaker ], PARAMS[0])
end

推荐阅读
mylvfamily
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有