子类实例变量在Ruby中更改超类实例变量

时间:2016-01-06 15:09:42

标签: ruby variables inheritance instance

在这两篇文章中:

  1. Instance Variables Inheritance

  2. Can Ruby subclass instance variables _overwrite_ the superclass's (same name)?

  3. 人们写的是关于在所有OOP语言中超类和派生类如何不具有单独的对象,并且当您创建派生类的实例时,它也是超类的实例。有一个对象,它同时是两个类。

    嗯,问题是我没有得到它?一个对象如何同时成为两个类?如果它们使用相同的名称,那么实例变量如何才能相同呢?

    我的意思是我从超类中获取子类获取方法,但我不知道他们如何共享实例变量?

    我查看了至少四本Ruby书籍,我发现的所有实例变量都不能通过继承链共享?

    有人可以简要解释"实例变量"从子类实际存储在超类?

2 个答案:

答案 0 :(得分:3)

这里要理解的关键是:实例变量与当前对象(或实例)相关联,而方法与类相关联。

原因是你不希望为每个创建的单个对象创建新方法,如果它们与该类的所有其他对象具有相同的主体。

另一方面,实例变量必须是每个对象的个体变量,否则在变异值时会有完整的混搭。

<小时/> 考虑到这一点,让我们考虑以下示例:

class Foo
  def foo
    @var = :foo
  end
end

class Bar < Foo
  def bar
    @var = :bar
  end
end

让我们探讨创建新对象时会发生什么:

baz = Bar.new

目前,baz没有任何实例变量。它只有一个指针,指示Bar是我的班级”

baz.class # => Bar

FooBaz类没有与@var关联的任何内容。所以目前,没有人知道@var

<小时/> 当您在baz上调用方法时,会在Bar 祖先链中搜索方法定义:

baz.class.ancestors # => [Bar, Foo, Object, Kernel, BasicObject]

你可以在这里注意一些事项:首先,那里的东西按照继承的顺序出现。其次,Foo隐含地继承自Object。第三,模块也可以是链的一部分(如Kernel)。

baz.bar # => :bar

会在链中找到第一个有方法#bar并调用它的东西。该值将分配给@var实例变量,该变量与对象baz相关联,而不是与FooBar类相关联。

baz.foo # => :foo

现在将使用Foo中的方法定义。但同样,@var正在更改baz

<小时/> 未来阅读的一些相关内容 (因为上面的一些内容因为简单起见并不完全准确)

  • 单身人士课程
  • 类变量
  • 包括/前置模块
  • Class.superclass # => Module
  • BasicObject#method_missing

答案 1 :(得分:1)

而不是让我们考虑真实的东西。

说你有宠物的概念,并且假设所有宠物都有一个名字。现在让我们说你有PetDog的概念,就像所有宠物都有一个名字一样,但也有一个“品种”。

正如你所看到的,完全合理地想到一个PetDog,作为Pet(它的超类)和PetDog(Pets的子类)

在数学上,您可以将一组具有相似特征的所有对象视为一类,然后子类“包围”超类,并具有更多特征。

class Food
  attr_accessor :name
end

class Fruit < Food
  attr_accessor :ripeness
end

banana = Fruit.new
banana.ripeness = 0 # very green banana
banana.name = "banana"  

steak = Food.new
steak.ripeness = 3 # ERROR... the base class Food does not know about "ripeness"

真实(工作)的例子怎么样?让我们使用react.rb DSL来定义时钟和警报UI组件

Clock组件类是React :: Component :: Base的子类,因此得到很多“状态”,它是基类的一部分。它知道如何渲染到html,它知道如何在事物更新时做出反应等。这个基类的所有部分,以及控制它并使其工作的所有数据都保留在基类中。

另外,Clock ihas有一些特殊属性,即它跟踪@clock变量中的当前时间。它也会每秒更新一次。

然后我们创建一个子类,称为Alarm。

因为Alarm是Clock的子类,它有内部的@clock变量(实际上是时钟类的一部分),和任何其他Clock一样,Alarms每秒更新一次。 这很重要!请注意,正是Clock类初始化了@clock变量,它也是使用时钟更新(重新显示)本身的Clock类。当Alarm继承自Clock时,@clock变量必须保持时钟的一部分,以使其正常运行。

但另外警报使用@clock变量来达到自己的目的,即检查并查看“时间到了”,当它启动时,它可以很好地阻止时钟运行(请注意,即使显示警报后,时钟继续运行,但闹钟没有。

希望这有帮助 - 确保运行示例!

<div id="container"></div>
<script type="text/ruby">
class Clock < React::Component::Base
  # a component that displays the time
  after_mount do 
    @clock = every(1) { force_update! }
  end
  def render
    "#{Time.now}"
  end
end

class Alarm < Clock
  # a kind of clock that notifies its caller when time is up!
  param :at, type: Time
  param :notify, type: Proc
  before_update do  
    # before_update is a feature of React::Component::Base
    # the following code is executed before each update of the Alarm
    if Time.now > params.at
      params.notify
      @clock.stop
    end
  end
  def render
    "Alarm will go off in #{(params.at-Time.now).to_i} seconds"
  end
end

Element['#container'].render do
  div do
    # This is react.rb's way of creating a new instance of Clock
    # Its shorthand for doing a Clock.new() and a bunch of other stuff
    Clock()  
    br
    Alarm(
     at: Time.now+10.seconds, 
     notify: -> { alert ('beep beep beep') }
    )
  end
end

</script>


<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<script src="https://rawgit.com/reactive-ruby/inline-reactive-ruby/master/inline-reactive-ruby.js"></script>