使用 ActiveSupport ``delegate to:'' 到 DRY presenters 实例方法

use ActiveSupport ``delegate to:'' to DRY presenters instance methods

由于 Ryan Bates' tutorial,我发现了演示者(或装饰者)模式并在培训项目中实施了它。

我想知道是否有任何方法可以在自定义对象之间使用 ActiveSupport delegate 方法? 重构我的第一个模型(产品)后,我想在 CartPresenter 实例中使用一些 ProductPresenter 实例方法。如果不是,也许我应该使用演示者的顾虑?

我目前正在视图中实例化演示者并通过将缺少的方法重定向到模板来访问辅助方法,但也许我需要在控制器中实例化演示者(以便访问 CartPresenterProductPresenter) 并为模板定义一个 getter (因此它不会混淆 method_missing 方法) ?


编辑

感谢 jvillian 的回答,:product_presenter 现在指的是 ProductPresenter 实例。

由于我可能在其他情况下需要委托演示者方法,因此我将 :delegated_presenter 添加到我的 BasePresenter

Class BasePresenter
  def initialize(object, template)
    @object = object
    @template = template
  end

  def self.delegated_presenter(name)
    define_method("#{name}_presenter") do
      klass = "#{name.capitalize}Presenter".constantize
      @delegator ||= klass.new(@object.send(name), @template)
    end
  end
end

现在在我的演示者子里面classes :

class CartPresenter < BasePresenter
  delegated_presenter :product
  delegate :product_presenter_instance_method, to: :product_presenter
end

我正在考虑将它们组合成一个 BasePresenter class 方法来完成所有工作。

这是它在视图中的用法:

<% present product do |product_presenter| %>
  <div class="card" style="width: 14rem;">
    <%= product_presenter.display_card_image %>
    <div class="card-body">
      <%= product_presenter.display_link_to_product_name(class: 'card-title text-dark') %>
      <%= product_presenter.display_link_to_product_supplier(class: 'small text-right') %>
      <%= product_presenter.display_truncated_description(class: 'card-text') %>
      <%= render partial: 'product_buttons', locals: { product: product } %>
      <%= product_presenter.display_tags(class: 'badge badge-pill badge-secondary') %>
    </div>
  </div>
<% end %>

present 是 returns 演示者对象的辅助方法。

这个:

delegate :my_instance_method, to: :product_presenter

...不起作用,因为 :product_presentersymbol,而不是 ProductPresenter 的实例。也许尝试更像:

class CartPresenter

  delegate :my_instance_method, to: product_presenter 

  def product_presenter
    @product_presenter ||= ProductPresenter.new 
  end

end

...和...

class ProductPresenter

  def my_instance_method
    # do something
  end

end

这条语句:

I'm currently instantiating presenters inside views

...我有点担心,因为您在视图和演示者之间建立了紧密的耦合。这是一个较长的主题,但如果我生成您在代码中显示的视图,它看起来更像是:

<% @presenter = local_assigns[:presenter] if local_assigns[:presenter] %>

<div class="card" style="width: 14rem;">
  <%= @presenter.card_content %>
</div>

然后,自然而然地,无论您使用 locals 传入的演示者都需要实现 card_content。现在,您的视图对 presenter 或其方法 一无所知 或除此方法 card_content 之外的其他方法。您可以在 card_content 中做任何您想做的事,并在以后对 product_presenter 方法进行更改,而无需担心更新您的视图。解耦!