2

我在我的 Rails 项目中使用 Draper gem 来获取装饰器模式功能。我认为 gem 将通过分离模型逻辑和视图逻辑来帮助提高我的工作效率。但是整个工作流程变得可怕。我应该始终将 .decorate 添加到每个控制器中的模型中。我的装饰器类是相互之间的委托全网。此外,当我开始使用 ActiveModel 序列化器时,我发现序列化器无法与我的装饰器一起使用。

我不喜欢这种方法并决定不使用单独的装饰器类,而是为每个模型提供装饰器模块。可以吗?这个解决方案可能会出现什么问题?

module UserDecorator
  extend ActiveSupport::Concern

  included do
    def full_name
      "{first_name} #{last_name}"
    end
  end
end

首先,它非常简单。我解决了下一个问题:

  1. 我不需要使用装饰继承的模型类。我只是为现有模型类提供装饰器方法。

  2. ActiveSerializer 现在可以使用装饰器方法。

但我觉得这个解决方案有问题。请给我一些批评!

4

1 回答 1

1

无论哪种方式都有效。

在共享这些关注点的模型上使用包含的装饰器关注点很好。

为每个需要装饰的模型使用装饰器类也很好。

当你说你“总是添加.decorate到每个控制器中的 [每个] 模型”时,代码不会“闻起来”。Draper gem 上的自述文件说你应该尽可能晚地推迟装饰;也就是在视图内。

可以从控制器传递一个装饰到相应的视图,但你也可以传递原始的、未装饰的对象,让视图选择何时需要装饰。仅仅因为你可以装饰每个对象并不意味着你应该。

让装饰器类具有“彼此之间的 delegate_all 网络”(具有跨模型装饰)也没有很好的“代码气味”。

让父类装饰器引用关联的对象装饰是很常见的;这就是很好的面向对象设计。例如:

report = Report.where("date < ?", selected_date)
report.decorate
report.line_items.decorate

但是,如果您最终在许多模型之间共享了许多公共装饰,那么干掉您的代码建议在某处使用公共装饰器 - 在父装饰器类中或在共享模型关注点中。

我认为您不应该尝试序列化装饰;序列化应该发生在模型本身上。或者,对需要特殊情况序列化的属性使用不同的装饰。

于 2016-04-28T08:09:10.113 回答