2009-09-27 18 views
25

Próbuję napisać najbezpieczniejsze singleton w Ruby, że mogę. Jestem nowy w języku, który jest tak elastyczny, że nie mam silnego wrażenia, że ​​moja klasa singletona odniesie sukces w tworzeniu tylko jednej instancji. Jako bonus chciałbym, aby obiekt stał się instancją tylko wtedy, gdy jest naprawdę używany.Jaki jest poprawny sposób zapisu wzorca singleton w Ruby?

Odpowiedz

43
# 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 

Co robi rubin, gdy w klasie znajduje się moduł singleton?

  1. Powoduje, że metoda new jest prywatna, więc nie można z niej korzystać.
  2. Dodaje metody klasy o nazwie instancji, który tworzy wystąpienie tylko jedną instancję klasy.

więc użyć modułu Ruby singleton potrzebne są dwie rzeczy:

  1. wymagają lib singleton następnie umieścić go wewnątrz żądanej klasy.
  2. Użyj metody instance uzyskać instancję trzeba.
16

Jeśli chcesz utworzyć singleton, po co tworzyć klasę? Po prostu utwórz obiekt i dodaj do niego odpowiednie metody i zmienne instancji.

>> 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 

bardziej standardowy sposób, że ludzie wdrożenia tego wzoru jest użycie Module jako singleton obiektu (zamiast bardziej ogólny 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" 

Jeśli chciał swoją singleton obiektu do dziedziczenia z jakąś klasę, po prostu uczyń ją instancją tej klasy. Aby odziedziczyć po mixinie, po prostu użyj #extend. Jeśli chcesz obiekt singleton, ruby ​​czyni go naprawdę łatwym, i w przeciwieństwie do innych języków, nie musi być zdefiniowany w klasie.

Ad-hoc singletons (mój pierwszy przykład) są wszędzie, a pokrycie większości przypadków, z jaką się spotkałem. Podejście modułowe zwykle obejmuje resztę (kiedy chcę czegoś bardziej formalnego).

Kod Rubiego powinien (imho) używać typowania kaczego (przez #respond_to?) zamiast jawnie sprawdzać klasę obiektu, więc normalnie nie dbam o wyjątkowość klasy moich obiektów singleton, ponieważ to nie jest jej klasa, która sprawia, że wyjątkowy, ale wszystko, co dodałem po.

+6

+1 za wskazanie, że pojedyncza nie jest naprawdę potrzebne. Możesz zrealizować intencję bez niewolniczo kopiowania wzorca. –

+0

Ciężko o tym myślałem, ponieważ kwestionuje to samo istnienie modułu Singleton w rdzeniu rubinowym. Potencjalna użyteczność klasy w/Singleton mixin uderza mnie podwójnie: 1) jeśli chcesz mieć dwie metody klasy i instancji oraz 2) jeśli masz skomplikowaną inicjalizację, którą chcesz uruchomić leniwie, bez konieczności stosowania metod modułu, aby jakoś wyzwolić go jawnie po raz pierwszy są dostępne. Czy ktokolwiek inny ma jakieś zalety rzeczywistego modułu Singleton? – gtd

Powiązane problemy