如何正确摧毁一个阶级

Gab*_*lin 4 ruby finalizer resource-cleanup

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

class Animal
 ...
end

class Mammal < Animal
 ...
end

class Feline < Mammal
 ...
end

class Cat < Feline
 ...
end

class Lion < Cat
 ...
end

...
Run Code Online (Sandbox Code Playgroud)

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

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

  // Execute clean up code for Parent class
  parent::__destruct();
}
Run Code Online (Sandbox Code Playgroud)

我可以为所有类提供类似的方法,除了Animal.由于它没有扩展任何内容,因此该parent::__destruct();行不再有效.

但是,据我所知,Ruby没有像这样的方法用于它的对象.可以设置终结器,但我决定cleanup只要我想要销毁/删除一个类就可以调用一个方法.这会照顾我在设置课程之前需要做的任何事情nil.

这引发了一个新问题.如果方法总是被命名cleanup并且我打电话lion_instance.cleanup,我认为它调用了Lion#cleanup.然后如何让它cleanup在课堂上调用Cat然后Feline在链上?

或者这是一个错误的方法,你有一个更好的主意?

Way*_*rad 6

这个Ruby的习惯用法是生成一个可以正常运行的块,当块返回时,进行清理.Ruby的内置"File.open"执行此操作:

File.open("/tmp/foo") do |file|
  file.puts "foo"
end
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

并使用它:

Foo.open do |foo|
  # use foo
end
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

和两个派生类:

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
Run Code Online (Sandbox Code Playgroud)

使用:

Foo.open do |foo|
  # use foo
end

Bar.open do |bar|
  # use bar
end
Run Code Online (Sandbox Code Playgroud)

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

  def self.open(*args)
     foo = new(*args)
     begin
       yield foo
     ensure
       foo.close
     end
  end
Run Code Online (Sandbox Code Playgroud)

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