2014-05-09 35 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" 
)