2016-04-06 20 views
0

我試圖在Java中使用慣用Ruby來實現Facade。我可以看到Rails的ActiveRecord喜歡使用類方法來處理像find_by(criteria)這樣的事情,並且不使用Repository模式來執行該任務。在Ruby中慣用地創建門面

我的Facade用幾種方法包裝了一個特定的webservice。我最初的想法是做它的API類似ActiveRecord(模仿學習):

class MyEntity 
    # .... 

    def get_name 
    @loaded_name + @loaded_surname 
    end 

    def delete 
    @entity_access_service.delete(@id) 
    end 

    def save 
    @entity_access_service.save(@id, @loaded_name , @loaded_surname) 
    end 

    def self.find(id) 
    data = @entity_access_service.get_data_for(id) 
    MyEntity.new(data) #Or whatever way to populate my entity 
    end 
end 

這在理論上,將工作的偉大:

e = MyEntity.find(10) 
p e.get_name 
e.delete 

或者:

e = MyEntity.new(some stuff) 
e.save 

問題: 對於savedelete實例方法的工作,我需要一些如何獲得EntityAccessService的實例。這個實例應該可以在孤立的環境中進行測試。什麼是正確的方法來做到這一點?

我期待我的測試看起來儘可能簡單,沒有一些奇怪的黑客,因爲我試圖實現似乎相當微不足道。

我想到了幾個選項來做到這一點:

  1. 有一個類級變量持有所有應用程序創建的實體使用entity_access_service。在這種情況下,我應該在哪裏初始化這個字段?例如:

    class MyEntity 
        @@entity_access_service = nil 
    end 
    
    # Somewhere else (where?): 
    MyEntity.entity_access_service = MyEntityService.new(some_params_from_env) 
    

    這樣,在我的測試中,我將不得不在啓動時初始化/模擬它。

  2. 與1類似,但在類中初始化它。這看起來很奇怪,特別是如果我知道我的測試完全不需要ENV params。

  3. 有一個額外的構造函數/屬性來設置entity_service。這將不起作用,因爲save不會對此字段進行初始化。

  4. 創建一個Repository類。這會工作得很好,但似乎不是Ruby人所做的。

+0

你可以在方法定義和方法調用中都省略空括號。 – Stefan

+0

@Stefan完成:) – bezmax

+1

你*可*,這並不意味着你*應*。這是一個意見/個人選擇,而不是對snake_case的強烈偏好。 –

回答

1

以下是ActiveRecord的示例,您可以在您自己的類或者派生其他類的基類上創建一個方法。

ActiveRecord提供了一種方法ActiveRecord::Base.connection,它返回所有模型用來訪問數據庫的連接對象。你可以做同樣的事情:

class MyEntity 
    .... 

    def self.entity_access_service 
     # return your service object 
    end 

    def self.find(id) 
     MyEntity.entity_access_service.get_data_for(id) 
     MyEntity.new(data) # Or whatever way to populate my entity 
    end 

    def save() 
     MyEntity.entity_access_service.save(@id, @loadedName, @loadedSurname) 
    end 
end 

至於初始化的話,你要麼必須在你的應用程序一個初始化步驟(和測試套件),其中服務的憑證從配置文件讀取並傳遞到您的MyEntity對象, entity_access_service方法可以懶洋洋地創建它第一次訪問使用很常見的Ruby成語返回對象:

def self.entity_access_service 
    @entity_access_service || = # build entity_access_service object 
end 

需要注意的是,在類級別的訪問方法包裝類級別的實例變量,你可以避免使用@@這是一個recommended best practice

+0

鑑於我正在使用Rspec,我應該在哪裏模擬此服務?我是否應該創建一個實例雙精度,並在運行測試之前將其直接寫入MyEntity.service_field?或者我應該爲這個字段創建一種'self.initialize_entity_service(service)'方法作爲「setter」?或者,我是否應該對MyEntity類進行部分加倍,嘲笑整個方法'self.entity_access_service'? – bezmax

+0

是的,以instance_double!你如何提供雙倍的答案真的取決於你想要你的api的樣子。如果按照上面提到的類實例化訪問服務本身的方法,則可以模擬任何調用實例化訪問服務並返回實例double。或者,您可以爲訪問服務提供setter,並使用before塊設置測試中的值。我可能會傾向於類實例化路徑;類設置器路徑可能意味着某個地方有一大組初始化器。 – AndyV