这个例子的目的是什么来自' Rails反模式'书:class<< ActiveRecord类中的自定义方法

时间:2014-09-17 11:11:20

标签: ruby-on-rails ruby oop activerecord encapsulation

我花了一些时间再次阅读Rails Antipatterns。在页81,有一个示例将属性非规范化为模型上的文本字段。我会简化这个例子;请假设state是文章表中的一列:

class Article < ActiveRecord::Base
  STATES = %w(review published)
  validates :state, :inclusion => {:in => STATES}

  STATES.each do |state|
    define_method "#{state}?" do
      self.state == state
    end
  end

  class << self
    STATES.each do |state|
      define_method "#{state}" do
        state
      end
    end
  end
end

我试图解决的问题是在类&lt;&lt;类中定义的方法。自我阻止。当你说class&lt;&lt;自我并在那个黑色中定义方法,因为self是类文章,我正在定义文章的类方法,对吧? Article.review,Article.published。我只是看不出目的是什么。如果目的是设置一些访问器,为什么不在第一个“#{state}?”的上部循环中定义那些访问器。方法已定义。

这有什么问题吗?我在书上找了勘误,没找到任何东西。

3 个答案:

答案 0 :(得分:3)

本书中的例子是这个反模式的重构:

@article.state = State.find_by_name("published")

到此:

@article.state = State.published

然后到此:

@article.state = Article.published

最后一个是暗示的,未在书中显示。

正如你所注意到的那样,制作一个只返回自己名字的类方法似乎没什么意义,所以这个例子的真正意义并不在于这是做事的最佳方式,而是作为书。陈述:

  

最重要的是它没有代表的复杂性和代码。

即。动态创建的方法曾经在State类中,而且这个类是不必要的,可以删除。

然而,这样做还有另一个好处。定义方法的目的是使用标准化接口为DB列创建一组常量。最初,常量的名称将与访问器方法的名称相同,但将来可能有理由进行更改。在这种情况下,可以调用这些访问器方法的程序的其他区域可以保持不变。

将此与在整个地方硬编码常量的实际字符串值的替代方法进行对比。在这种情况下,Article的数据库结构的知识泄漏并创建依赖关系,因此对Article类内部(DB结构)的更改将会波及其他具有不可预测影响的区域。通过使用消息而不是常量的实际值,这些依赖关系将被删除,并且如果需要重构,任何重构都将是微不足道的。您可以轻松地将任何这些动态方法重新定义为更复杂的东西,而不会导致Article之外的任何其他内容需要更改。

换句话说:为了正确封装数据,良好的OO设计要求知道数据库列的名称不应该离开Article类。你应该总是更喜欢方法而不是变量,以使这成为可能,这就是那个类方法的作用。

答案 1 :(得分:0)

第二个循环是在Article上定义类方法,它返回每个状态的字符串表示。那是Article.review返回"review"

答案 2 :(得分:0)

在红宝石中,那两个下一个区块是相同的

class MyClass
  class << self
    def my_method
      puts 'this is a method'
    end
  end
end

和这个块

class MyClass
  def self.my_method
    puts 'this is a method'
  end
end

您只是避免为您定义的每个类方法键入self

您可以参考此blog post获取更详细的解释