使用 ActiveSupport ``delegate to:'' 到 DRY presenters 实例方法
use ActiveSupport ``delegate to:'' to DRY presenters instance methods
由于 Ryan Bates' tutorial,我发现了演示者(或装饰者)模式并在培训项目中实施了它。
我想知道是否有任何方法可以在自定义对象之间使用 ActiveSupport delegate
方法?
重构我的第一个模型(产品)后,我想在 CartPresenter
实例中使用一些 ProductPresenter
实例方法。如果不是,也许我应该使用演示者的顾虑?
我目前正在视图中实例化演示者并通过将缺少的方法重定向到模板来访问辅助方法,但也许我需要在控制器中实例化演示者(以便访问 CartPresenter
和 ProductPresenter
) 并为模板定义一个 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_presenter
是 symbol
,而不是 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
方法进行更改,而无需担心更新您的视图。解耦!
由于 Ryan Bates' tutorial,我发现了演示者(或装饰者)模式并在培训项目中实施了它。
我想知道是否有任何方法可以在自定义对象之间使用 ActiveSupport delegate
方法?
重构我的第一个模型(产品)后,我想在 CartPresenter
实例中使用一些 ProductPresenter
实例方法。如果不是,也许我应该使用演示者的顾虑?
我目前正在视图中实例化演示者并通过将缺少的方法重定向到模板来访问辅助方法,但也许我需要在控制器中实例化演示者(以便访问 CartPresenter
和 ProductPresenter
) 并为模板定义一个 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_presenter
是 symbol
,而不是 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
方法进行更改,而无需担心更新您的视图。解耦!