2014-05-09 63 views
2

我有一個記錄/模型,充滿了很多布爾標誌,短字符串,混雜設置等,我想重構它們到一個封裝類。Ruby on Rails OOP - 我知道嵌套/內部類,嵌套'記錄'怎麼樣?

我通常會爲父母創建一個「自己」的內部類,但是Rails中的最佳實踐是什麼?

  • 只留下一切記錄? composed_of?雖然不是很乾淨。
  • 序列化?變得不容易搜索+開銷+可擴展性問題。仍然不乾淨。
  • 創建另一條記錄,關聯它和delegate?但必須委派和管理任務,別名(布爾?字段),創建/保存回調,我不知道更多的東西...
  • 有沒有一種方法來創建'內部記錄'?
  • 另一種方式?

一個例子是有一個表Client,行數低10〜20。每個Client都有很長的選項列表,目前存儲在Client列。因此,有領域,如:

c = Client.find(1) 
c.theme_color # "blue" 
c.session_timeout_seconds # 1800 
c.branding_logo # "client_a.png" 
c.require_logout_confirmation # true 

在純面向對象系統沒有護欄,我會重構這些「實例變量」到嵌套Client::Options類。然後,所有選項都將組織在一個嵌套類中,並封裝在Client內。這樣,沒有其他人需要知道Client::OptionsClient是密切相關的(它們仍然只是消息c.theme_color而不知道Client會將呼叫委託給內部的Client::Options),並且這也將成爲鬆散耦合的重構,因爲沒有其他類或方法調用需要改變。

但是,嵌套類的東西是不可能的(據我所知)在軌道中,所以我正在尋找'最佳實踐'的解決方案。

+0

好像它會產生過於剛愎自用的答案。但我不知道。 – sevenseacat

+0

那麼那麼這意味着沒有'最佳實踐',我只需要做一些自定義解決方案。 – Kache

+0

爲什麼你想重構成封裝類?因爲它是有意義的(它們屬於一個整體,它應該是另一個實體),分享它,更容易地擴展它?也許一個更具體的例子來演示可能會有幫助。 – nathanvda

回答

0

這是我結束了去瞭解決方案:

class Client < ActiveRecord::Base 
    has_one :option_set, :dependent => :destroy, :autosave => true, :validate => true, :inverse_of => :client 
    before_create :build_option_set 

    # accesses all these fields through OptionSet 
    # :allow_nil is required or else delegation will fail - it appears delegation occurs before :build_option_set 
    delegate_option_set_args = [ 
    :option_a, 
    :option_b, 
    :option_c, 
    # etc 
    ].map { |f| [f, :"#{f}=", :"#{f}?" ] }.flatten << { :to => :option_set, :allow_nil => true } 

    delegate(*delegate_option_set_args) 
end 


class OptionSet < ActiveRecord::Base 
    validates_presence_of :client_id 
    validates_inclusion_of :option_c, :in => [ "foo", "bar", "buzz", "fizz" ] 
    belongs_to :client, :inverse_of => :option_set 
end 

如今,雖然OptionSet還是從Client「外」訪問,但它仍然有效地封裝了所有這些領域納入自己的類。訪問這些字段應通過發送消息Client來完成,例如, Client.first.option_a,而不是修改OptionSet。可以執行額外的工作來強制OptionSet未被直接修改。

我還沒有找到一種方法,同時爲Client創建實例化選項字段,但:

client = Client.create!(client_args) 
client.update_arguments!(
    :option_a => 1, 
    :option_b => false, 
    :option_c => "foo" 
)