使用来自另一个类的方法包装对象

ker*_*lin 2 ruby methods ruby-on-rails

假设我有一个名为Article的模型:

class Article < ActiveRecord::Base
end
Run Code Online (Sandbox Code Playgroud)

然后我有一个用于向文章对象(装饰器)添加行为的类:

class ArticleDecorator

  def format_title
  end

end
Run Code Online (Sandbox Code Playgroud)

如果我想扩展一个文章对象的行为,我可以使ArticleDecorator成为一个模块,然后调用article.extend(ArticleDecorator),但我更喜欢这样的东西:

article = ArticleDecorator.decorate(Article.top_articles.first) # for single object
Run Code Online (Sandbox Code Playgroud)

要么

articles = ArticleDecorator.decorate(Article.all) # for collection of objects
Run Code Online (Sandbox Code Playgroud)

我将如何实现这种装饰方法?

KL-*_*L-7 5

你究竟想从decorate方法中得到什么?它应该只是为传递的对象添加一些新方法,还是应该使用相应的格式方法自动包装这些对象的方法?为什么你想ArticleDecorator成为一个班级而不仅仅是一个模块?

更新:

看起来像nathanvda的解决方案是你需要的,但我建议一个更清洁的版本:

module ArticleDecorator

  def format_title
    "#{title} [decorated]"  
  end

  def self.decorate(object_or_objects_to_decorate)
    object_or_objects_to_decorate.tap do |objects|
      Array(objects).each { |obj| obj.extend ArticleDecorator }
    end
  end

end
Run Code Online (Sandbox Code Playgroud)

它做同样的事情,但是:

  1. 避免依赖于Kernel#Array方法检查参数的类型.
  2. Object#extend直接调用(这是一个公共方法,所以不需要调用它send).
  3. Object#extend仅包含实例方法,因此我们可以将它们直接放入,ArticleDecorator而不用另一个模块包装它们.