在两个类之间共享一个类实例

时间:2014-05-21 19:26:43

标签: ruby

我有两个不同的类,它们都代表需要持久化到我的数据库的对象,现在我想在两个类之间共享数据库客户端对象。我想避免多次实例化客户端对象。

目前我通过使用全局变量

来做到这一点
$client = Mysql2::Client.new(:database => "myDb", :user => "user", :password => "password", :host => "localhost")

class Person
  def save
    $client.query("INSERT INTO persons")
  end
end

class Car
  def save
    $client.query("INSERT INTO cars")
  end
end

这有效,但我想知道是否有更正确的方法可以做到这一点以及为什么它们更正确?

2 个答案:

答案 0 :(得分:3)

您可以从父类继承。这允许您跨对象共享通用功能,并遵循DRY(不要重复自己)编程原则。它还允许您使用锁,结果,队列,池以及您可能想要执行的任何其他操作来保护您的数据库连接,而无需在您的子类中担心它

class Record
  @table_name = nil
  @@client = Mysql2::Client.new(:database => "myDb", :user => "user", :password => "password", :host => "localhost")

  def save
    @@client.query("INSERT INTO #{@table_name}") if @table_name
  end
end

class Person < Record
  @table_name = "persons"
end

class Car < Record
  @table_name = "cars"
end

在讨论这个主题时,您应该考虑使用ActiveRecord来处理数据库模型和连接。它已经完成了你需要的任何东西,并且将与已经存在的其他宝石更加兼容。 It can be used without rails

答案 1 :(得分:1)

作为使用继承的替代方法,为什么不考虑一个简单的Singleton pattern?通过将类外的责任分开,这可以使您的模型更清洁。并且不需要继承。

以下示例说明了这一点。只能存在一个DataManager类的单个实例。所以,你只会实例化一次 - 但可以在任何地方使用它:

require 'singleton'

class DataManager
  include Singleton

  attr_accessor :last_run_query

  def initialize()
    if @client.nil?
      p "Initialize the Mysql client here - note that this'll only be called once..."
    end
  end

  def query(args)
    # do your magic here
    @last_run_query = args
  end

end

接下来,使用.instance访问器调用它是一件轻而易举的事 - 并且总是指向一个单独的实例,如下所示:

# Fetch, or create a new singleton instance
first = DataManager.instance
first.query('drop table mother')
p first.last_run_query

# Again, fetch or create a new instance
# this'll actually just fetch the first instance from above
second = DataManager.instance
p second.last_run_query

# last line prints: "drop table mother"

对于记录,Singleton模式可能有一些缺点,使用它经常导致a never-ending debate是否应该使用它。但在我看来,它是你特定问题的一个不错的选择。