Подтвердить что ты не робот

Каков правильный способ написания шаблона singleton в Ruby?

Я пытаюсь написать самый безопасный синглтон в Ruby, который я могу. Я новичок в языке, который настолько эластичен, что у меня нет сильного чувства, что мой одноэлементный класс будет успешным при создании только одного экземпляра. В качестве бонуса, я бы хотел, чтобы объект только стал экземплярным, если он действительно использовался.

4b9b3361

Ответ 1

# require singleton lib
require 'singleton'
class AppConfig
  # mixin the singleton module
  include Singleton
  # do the actual app configuration
  def load_config(file)
    # do your work here
    puts "Application configuration file was loaded from file: #{file}"
  end
end

conf1 = AppConfig.instance
conf1.load_config "/home/khelll/conf.yml"
#=>Application configuration file was loaded from file: /home/khelll/conf.yml
conf2 = AppConfig.instance
puts conf1 == conf2
#=>true
# notice the following 2 lines won’t work
AppConfig.new rescue(puts $!)
#=> new method is private
# dup won’t work
conf1.dup rescue(puts $!)
#=>private method `new’ called for AppConfig:Class
#=>can’t dup instance of singleton AppConfig

Итак, что делает ruby, когда вы включаете модуль singleton внутри своего класса?

  • Это делает метод new закрытым, поэтому вы не можете его использовать.
  • Он добавляет метод класса, называемый экземпляром, который создает экземпляр только одного экземпляра класса.

Итак, для использования модуля ruby ​​singleton вам нужны две вещи:

  • Требовать lib singleton, затем включить его в желаемый класс.
  • Используйте метод instance, чтобы получить необходимый экземпляр.

Ответ 2

Если вы хотите создать синглтон, зачем беспокоиться о создании класса? Просто создайте объект и добавьте нужные ему методы и переменные экземпляра.

>> MySingleton = Object.new
=> #<Object:0x100390318>
>> MySingleton.instance_eval do
?>   @count = 0
>>   def next
>>     @count += 1
>>   end
>> end
=> nil
>> MySingleton.next
=> 1
>> MySingleton.next
=> 2
>> MySingleton.next
=> 3

Более стандартный способ реализации этого шаблона - использовать Module как объект singleton (а не более общий Object):

>> module OtherSingleton
>>   @index = -1
>>   @colors = %w{ red green blue }
>>   def self.change
>>     @colors[(@index += 1) % @colors.size]
>>   end
>> end
=> nil
>> OtherSingleton.change
=> "red"
>> OtherSingleton.change
=> "green"
>> OtherSingleton.change
=> "blue"
>> OtherSingleton.change
=> "red"

Если вы хотите, чтобы ваш объект singleton наследовался от какого-либо класса, просто сделайте его экземпляром этого класса. Чтобы наследовать из mixin, просто используйте #extend. Если вам нужен одноэлементный объект, рубин делает его очень легким, и в отличие от других языков его не нужно определять в классе.

Ad-hoc singletons (мой первый пример) повсюду и охватывают большинство случаев, с которыми я столкнулся. Трюк модуля обычно охватывает остальные (когда я хочу что-то более формальное).

Ruby-код должен (imho) использовать утиную печать (через #respond_to?) вместо явной проверки класса объекта, поэтому я обычно не забочусь о уникальности моего класса объектов singleton, так как это не его класс, который делает он уникален, но все, что я добавил после.