2011-03-10 112 views
17

我已經知道如何定義一個類爲一單(how to create a singleton in ruby):紅寶石 - 用參數創建單例?

require 'singleton' 

class Example 
    include Singleton 
end 

但是如果我想給它一些參數對於單個實例,這意味着,該實例應該始終有一定的性能初始化。例如,假設我有一個課程,其唯一目的是登錄到一個文件(這僅僅是一個例子),但它需要一個文件的名稱才能登錄才能工作。

class MyLogger 
    def initialize(file_name) 
    @file_name = file_name 
    end 
end 

我該如何讓MyLogger成爲一個singleton,但確保它獲得file_name?

+1

,你確定你想使用單? – 2011-03-10 12:22:49

+2

是的。我相信有些情況下單身人士是有道理的,但它應該有一些初始配置。 – codecraig 2011-03-10 12:30:49

回答

4

辛格爾頓不提供此功能,但使用的單,你可以自己

class MyLogger 
    @@singleton__instance__ = nil 
    @@singleton__mutex__ = Mutex.new 
    def self.instance file_name 
    return @@singleton__instance__ if @@singleton__instance__ 
    @@singleton__mutex__.synchronize { 
     return @@singleton__instance__ if @@singleton__instance__ 
     @@singleton__instance__ = new(file_name) 
    } 
    @@singleton__instance__ 
    end 
    private 
    def initialize file_name 
    @file_name = file_name 
    end 
    private_class_method :new 
end 

它應該工作寫出來,但我沒有測試的代碼。

此代碼強制您使用MyLogger.instance <file_name>或至少在第一次通話時,如果您知道它將首次通話。

+0

謝謝,這個工程。 – codecraig 2011-03-10 12:31:08

+0

所以我想我必須在創建@@ __ singleton_instance__之後重寫self.new,否則您仍然可以執行MyLogger。新 – codecraig 2011-03-10 12:51:33

+0

好吧,這就是我想出來的: – codecraig 2011-03-10 13:01:24

1

這是太長,投入評論(如計算器說,這是太長)

好了,所以這裏就是我想出了:

class MyLogger 
    @@singleton__instance__ = nil 
    @@singleton__mutex__ = Mutex.new 
    def self.config_instance file_name 
    return @@singleton__instance__ if @@singleton__instance__ 
    @@singleton__mutex__.synchronize { 
     return @@singleton__instance__ if @@singleton__instance__ 
     @@singleton__instance__ = new(file_name) 
     def self.instance 
     @@singleton__instance__ 
     end 
     private_class_method :new 
    } 
    @@singleton__instance__ 
    end 
    def self.instance 
    raise "must call MyLogger.config_instance at least once" 
    end 
    private 
    def initialize file_name 
    @file_name = file_name 
    end 
end 

這將使用「config_instance」來創建和配置單例實例。一旦實例準備就緒,它會重新定義self.instance方法。

它也使'new'類方法在創建第一個實例後保密。

+0

固定在我的答案中,您可以在類級別設置新的女貞,新的將仍然可見def self.instance – mpapis 2011-03-10 13:18:06

13

這裏是另一種方式來做到這一點 - 在一個類變量將日誌文件名:

require 'singleton' 
class MyLogger 
    include Singleton 
    @@file_name = "" 
    def self.file_name= fn 
    @@file_name = fn 
    end 
    def initialize 
    @file_name = @@file_name 
    end 
end 

現在你可以使用這種方式:

MyLogger.file_name = "path/to/log/file" 
log = MyLogger.instance # => #<MyLogger:0x000.... @file_name="path/to/log/file"> 

後續調用instance將返回即使稍後更改了類變量的值,該路徑名的同一對象也不會改變。另一個更好的方法是使用另一個類變量來跟蹤一個實例是否已經被創建,並且在這種情況下有file_name=方法引發異常。如果尚未設置@@file_name,您還可以讓initialize發生異常。

+2

爲什麼麻煩複制@@ file_name到@file_name而不是隻使用@@ file_name如果它是單身呢? – Gavriel 2015-10-28 10:12:05

0

簡單單如果你想傳遞參數不依賴於Singleton模塊

class MyLogger 
    def self.instance(filepath = File.join('some', 'default', 'path')) 
    @@instance ||= new(filepath).send(:configure) 
    end 

    def initialize(filepath) 
    @filepath = filepath 
    end 
    private_class_method :new 

    def info(msg) 
    puts msg 
    end 

    private 

    def configure 
    # do stuff 
    self 
    end 
end 

用法示例

logger_a = MyLogger.instance 
# => #<MyLogger:0x007f8ec4833060 @filepath="some/default/path"> 

logger_b = MyLogger.instance 
# => #<MyLogger:0x007f8ec4833060 @filepath="some/default/path"> 

logger_a.info logger_a.object_id 
# 70125579507760 
# => nil 

logger_b.info logger_b.object_id 
# 70125579507760 
# => nil 

logger_c = MyLogger.new('file/path') 
# NoMethodError: private method `new' called for MyLogger:Class