如何正确摧毁一个阶级

时间:2012-09-21 19:16:18

标签: ruby finalizer resource-cleanup

在Ruby中,我有一个DAO类,它通过一个类来扩展,这使得管理连接变得更容易,这个类由表示和操作数据库中的数据的类扩展,该类由另一个类进一步扩展。使用动物比喻它看起来像这样:

class Animal
 ...
end

class Mammal < Animal
 ...
end

class Feline < Mammal
 ...
end

class Cat < Feline
 ...
end

class Lion < Cat
 ...
end

...

在PHP中,有一个__destruct方法在您销毁/删除类时运行。如果该类扩展了另一个类,您只需将parent::__destruct()添加到类的__destruct方法中,如下所示:

public function __destruct() {
  // Clean up code for this class here
  ...

  // Execute clean up code for Parent class
  parent::__destruct();
}

我可以为除Animal之外的所有类使用类似的方法。由于它没有扩展任何内容,parent::__destruct();行不再有效。

但是,据我所知,Ruby没有像这样的方法用于它的对象。可以设置终结器,但我决定只在我想要销毁/删除类时调用cleanup方法。在我将课程设置为nil之前,这将需要处理任何事情。

这引发了一个新问题。如果该方法始终命名为cleanup并且我调用lion_instance.cleanup,我认为它会调用Lion#cleanup。然后如何让它在课程cleanup中调用Cat,然后调用Feline并在链上调用?

或者这是一种错误的做法,你有更好的想法吗?

3 个答案:

答案 0 :(得分:6)

这方面的Ruby习惯是屈服于一个有效的块,当块返回时,做清理。 Ruby的内置“File.open”就是这样做的:

File.open("/tmp/foo") do |file|
  file.puts "foo"
end

当块结束时,文件将为您关闭,而您无需执行任何操作。这是一个很好的习语。以下是您可以实现类似的方法:

class Foo

  def self.open(*args)
     foo = new(*args)
     yield foo
     foo.close
  end

  def initialize
    # do setup here
  end

  def close
    # do teardown here
  end

end

使用它:

Foo.open do |foo|
  # use foo
end
{p> Foo#close将在end

后自动生成

这也适用于子类化。那是因为类方法和实例方法一样是继承的。这是超类:

class Superclass

  def self.open(*args)
    o = new(*args)
    yield o
    o.close
  end

  def initialize
    # common setup behavior
  end

  def close
    # common cleanup behavior
  end

end

和两个派生类:

class Foo < Superclass

  def initialize
    super
    # do subclass specific setup here
  end

  def close
    super
    # do subclass specific teardown here
  end

end

class Bar < Superclass

  def initialize
    super
    # do subclass specific setup here
  end

  def close
    super
    # do subclass specific teardown here
  end

end

使用:

Foo.open do |foo|
  # use foo
end

Bar.open do |bar|
  # use bar
end

如果确实需要确保无论如何都要进行清理,那么在类方法中使用 ensure 子句:

  def self.open(*args)
     foo = new(*args)
     begin
       yield foo
     ensure
       foo.close
     end
  end

这样,即使块中存在异常,也会发生清理。

答案 1 :(得分:2)

您可以使用ObjectSpace.define_finalizer

类似的东西:

class Animal
  def initialize
    ObjectSpace.define_finalizer(self, proc { # your code })
   end
end

答案 2 :(得分:1)

好吧,因为没有人回答你关于这个方法在继承链上移动的问题......

class Cat
  def rawr
    puts "rawr"
  end
end

class Kitty < Cat
  def rawr
    puts "meow"
    super
  end
end

Cat.new.rawr
"Rawr"

Kitty.new.rawr
"rawr"
"meow"

在方法中,您可以通过调用super来访问超类的同名方法。