【问题标题】:Is there a way to make only one class of a variable inherit from another class?有没有办法让一个变量的一个类从另一个类继承?
【发布时间】:2020-08-23 00:01:39
【问题描述】:

我是一个新手,也许我在搜索中遗漏了一些东西,但是我在这里查看了文档和其他问题,但没有找到我问题的答案,所以我会把它放在这里,如果有,请见谅它已经在其他任何地方进行了解释。 我有两个 ruby​​ 类,一个叫做 Animal,另一个叫做 Animal_Group。在 Animal 的初始化中,我有一个名为 @family 的变量,我想将此变量与 Animal_Group 的现有实例进行比较,如果有匹配项,我希望它继承定义(包括 Animal_Group 类初始化的值变量本身)的类 Animal_Group 及其实例。

只是为了说明,它会是这样的:

class Animal
  def initialize(ident, species, family, age)
    @ident = ident
    @species = species
    @family = family
    if family.class == Animal_Group
      super(*args)
    end
    @age = age
  end
end

所以它会导致这样的结果:

  1. 我创建了一个动物“工具包”,它是一只来自“猫”科的“猫”,年龄为 '7'。
  2. 有一个名为“feline”的 Animal_Group 实例,变量 @lifespan = '17'、@environment_sphere = 'terrestrial' 和 @breed_max = '6'
  3. 'kit' 是否有变量及其值如下:
@ident = 'kit'
@species = 'cat'
@family = 'feline'
@age = '7'
@lifespan = '17'
@environment_sphere = 'terrestrial'
@breed_max = '6'

有没有办法做到这一点,或者唯一的办法就是把所有东西都变成新的类?

【问题讨论】:

  • 考虑到类的实例没有名称,“有一个 Animal_Group 的实例称为 'feline'”是什么意思?

标签: ruby class inheritance


【解决方案1】:

基本上,如果没有元编程,这是不可能的。虽然我可以展示如何使用元编程来做到这一点,但我将把它作为练习留给读者,因为归根结底,最好保持简单,而且肯定有更简单的方法来做到这一点。

无论如何,我推荐的是这样的系统:

class AnimalGroup
  attr_reader :lifespan, :environment_sphere, :breed_max, :age
end

class Feline < AnimalGroup
  def initialize
    @lifespan = '17'
    @environment_sphere = 'terrestrial'
    @breed_max = '6'
  end
end

class Cat < Feline
  def initialize(age)
    @age = age
    super
  end
end

我知道这可能看起来没有您想要编写的代码那么灵活。我们没有将动物组的“类型”存储为动态实例变量,而是使用类定义对其进行硬编码。但希望您能看到这种方法更简单。

【讨论】:

  • 不要让我开始讨论将age 存储为变量而不是date_of_birth 然后从中计算age... :rolleyes:
【解决方案2】:

假设

class Animal_Group
  attr_reader :name, :lifespan, :breed_mix
  def initialize(name, lifespan, breed_mix)
    @name = name
    @lifespan = lifespan
    @breed_mix = breed_mix
  end
end
Animal_Group.new("Boots", 18, "Siamese")
  #=> #<Animal_Group:0x000056fa3111a878 @name="Boots", @lifespan=18,
  #     @breed_mix="Siamese"> 
Animal_Group.new("Hank", 14, "Tabby")
  #=> #<Animal_Group:0x000056fa3114f618 @name="Hank", @lifespan=14,
  #     @breed_mix="Tabby"> 

我假设Animal.new 中的参数family 的实例将是'Boots' 或'Hank',如

Animal.new('kit', 'Hank', 7)

如果我误解了这个问题,没有理由进一步阅读。

有两种方法可以使用来自Animal_Group 实例的信息来为Animal 实例的实例变量赋值。在这两种情况下,诀窍都是找到Animal_Group 的实例,其instance_variable @name 的值等于Animal.new 中参数family 的值

使用ObjectSpace::each_object

class Animal
  def initialize(ident, family, age)
    @ident = ident
    @family = family
    @age = age
    family_instance = ObjectSpace.each_object(Object).find do |o|
      o.class == Animal_Group && o.name == family
    end
    # raise exception here if family_instance is nil
    @lifespan = family_instance.lifespan
    @breed_mix = family_instance.breed_mix
  end
end
Animal.new('kit', 'Hank', 7)
  #=> #<Animal:0x000056fa31211f10 @ident="kit", @family="Hank",
  #     @age=7, @lifespan=14, @breed_mix="Tabby"> 
Animal.new('kat', 'Boots', 4)
  #=> #<Animal:0x000056fa31174918 @ident="kat", @family="Boots",
  #     @age=4, @lifespan=18, @breed_mix="Siamese">

维护Animal_Group的实例列表

class Animal_Group
  @name_to_instance = {}
  singleton_class.public_send(:attr_reader, :name_to_instance)
  attr_reader :name, :lifespan, :breed_mix
  def initialize(name, lifespan, breed_mix)
    @name = name
    @lifespan = lifespan
    @breed_mix = breed_mix
    self.class.name_to_instance[name] = self
  end
end

注意

singleton_class.public_send(:attr_reader, :name_to_instance)

(其中self #=&gt; Animal_Group)为类实例变量@name_to_instance 创建一个读取访问器,该变量包含一个将实例名称映射到实例的散列。

Animal_Group.new("Boots", 18, "Siamese")
  #=> #<Animal_Group:0x000056fa311b6110 @name="Boots", @lifespan=18,
  #     @breed_mix="Siamese"> 
Animal_Group.new("Hank", 14, "Tabby")
  #=> #<Animal_Group:0x000056fa311e9998 @name="Hank", @lifespan=14,
  #     @breed_mix="Tabby"> 

注意

Animal_Group.name_to_instance
  #=> {"Boots"=>#<Animal_Group:0x000056fa311b6110 @name="Boots",
  #      @lifespan=18, @breed_mix="Siamese">,
  #    "Hank"=>#<Animal_Group:0x000056fa311e9998 @name="Hank",
  #      @lifespan=14, @breed_mix="Tabby">} 
class Animal
  def initialize(ident, family, age)
    @ident = ident
    @family = family
    @age = age
    family_instance = Animal_Group.name_to_instance[family]
    # raise exception here if family_instance is nil
    @lifespan = family_instance.lifespan
    @breed_mix = family_instance.breed_mix
  end
end
Animal.new('kit', 'Hank', 7)
  #=> #<Animal:0x000056fa311fd9c0 @ident="kit", @family="Hank",
  #     @age=7, @lifespan=14, @breed_mix="Tabby"> 
Animal.new('kat', 'Boots', 4)
  #=> #<Animal:0x000056fa31212cf8 @ident="kat", @family="Boots",
  #     @age=4, @lifespan=18, @breed_mix="Siamese"> 

【讨论】:

    猜你喜欢
    • 2018-07-07
    • 2019-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-05
    • 2011-02-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多