【问题标题】:Best way to refactor complex dashboard重构复杂仪表板的最佳方法
【发布时间】:2013-06-09 19:44:04
【问题描述】:

TL;DR

我需要一种方法来重构包含多个对象和一些复杂数据的复杂用户仪表板,以显示会计图表。我的模型和控制器很乱,所以如果有人有一些提示或建议,我真的很感激:)!

长版:

我目前正在开发一个帮助用户协调晚餐俱乐部和所有相关会计的应用程序。 (晚餐俱乐部是一群人,轮流为剩下的人做饭,然后你支付少量费用参加。这在我所在的宿舍和大学里很正常)。当您登录时,您会看到一个仪表板,其中包含所有重要信息,分为三个部分:下一次晚餐和注册选项、下一次您必须做饭的晚餐以及当前债务、支出等会计概览。

这变得非常混乱:我的控制器中有很多实例变量,还有很多方法可以在我的模型中呈现这个视图。

现在回到真正的问题:谁能告诉我任何好的提示、设计模式或一般建议来帮助我重构这段代码?我已经阅读了有关演示者、服务对象、装饰器等的信息,但我不确定要使用哪个以及如何使用?

这里有一些现在看起来有多糟糕的例子(厨房是一群人一起吃晚饭):

# app/controllers/dashboard_controller.rb
def index
  @user = current_user
  @kitchen = @user.kitchen

  @upcoming_dinner_clubs = @user.upcoming_dinner_clubs # The next dinner clubs where the current user have to cook
  @users_next_dinner_club = @user.next_dinner_club # The first of upcoming_dinner_clubs
  @unpriced_dinner_clubs = @user.unpriced_dinner_clubs # Old dinner clubs where the user haven't specified a price yet

  # The next dinner club in the kitchen
  @next_dinner_club = @kitchen.next_dinner_club if @kitchen.next_dinner_club
  @todays_dinner_club = @next_dinner_club if @next_dinner_club && @next_dinner_club.date.today?
end

下面的视图显示了一些用户支出和支出的图表,通过 javascript 呈现。我的观点是不正确的。

# app/views/dashboard/_expenses.html.haml
%h2 Dit forbrug
  %p
    = t '.usage_html', expenses: number_to_currency(@user.last_month_expenses), spendings: number_to_currency(@user.last_month_spendings), results: number_to_currency(@user.last_month_results)
    = content_tag :div, "", id: "revenue_chart", class: "chart dashboard-chart", data: { chart: @user.usage_chart_data }
    = t '.results_html', results: number_to_currency(@user.total_results)
    = content_tag :div, "", id: "result_chart", class: "chart dashboard-chart", data: { chart: @user.result_chart_data }

不想让您对所有细节以及方法的工作方式感到厌烦,但这是我拥有的方法,仅用于在视图中显示费用和支出数据:

# app/models/user.rb
def last_month_expenses
  expenses_for((1.month + 1.day).ago, 1.day.ago)
end

def last_month_spendings
  spendings_for((1.month + 1.day).ago, 1.day.ago)
end

def last_month_results
  results_for((1.month + 1.day).ago, 1.day.ago)
end

def spendings_for(start_date, end_date, kitchen)
end

def expenses_for(start_date, end_date, kitchen)
end

def fee_for(start_date, end_date, kitchen)
end

def accounting_query_conditions(start_date, end_date, kitchen)
  {date: start_date..end_date, kitchen_id: kitchen.id}
end

def results_for(start_date, end_date)
  spendings_for(start_date, end_date) - expenses_for(start_date, end_date)
end

def total_fee(date = Date.today, kitchen = primary_kitchen)
end

def total_spendings(date = Date.today, kitchen = primary_kitchen)
end

def total_used_on_dinner_clubs(date = Date.today, kitchen = primary_kitchen)
end

def total_expenses(date = Date.today, kitchen = primary_kitchen)
end

def total_results(date = Date.today, kitchen = primary_kitchen)
  total_expenses(date, kitchen) - total_spendings(date, kitchen)
end

【问题讨论】:

  • 不要;你不使用装饰器/演示器吗?
  • 不,但我绝对应该:D!但是我不确定如何以最好的方式实现这一点,我认为上面的例子是一个很好的用例来学习它:)。
  • 实际上,从您在那里编写的代码中,我看不出装饰器中没有什么可以抽象的。我也没有看到任何糟糕的设计。您在对象中的方法是有意义的,并且代码非常易读。您在控制器中的实例变量中抽象了很多数据(我不会这样做),但为什么不...
  • 你会怎么做?将方法调用链接到用户?
  • 是的,就像你写@user.last_month_expenses时所做的一样

标签: ruby-on-rails ruby-on-rails-3 design-patterns refactoring


【解决方案1】:

让我们从一个规则开始,看看我们能走多远:

控制器中只有 1 个实例变量

为了遵循此规则,我认为您可能希望创建一个 UserDashboard 对象

class UserDashboard

  attr_reader :user
  def initialize(user)
    @user = user
  end

  def kitchen
    user.kitchen
  end

  def todays_club
    next_dinner_club if next_dinner_club && next_dinner_club.date.today?
  end

end

所以,在你的控制器中:

def index
  @dashboard = UserDashboard.new current_user
end

通过这种方式,您将所有关于俱乐部的逻辑以及其他任何内容都放在仪表板对象上,而不是放在控制器或用户对象中。这是一个类似于演示者的模式。

【讨论】:

  • 有道理!我将尝试实现这一点,然后更新我的问题。然而,由于这解决了一些问题,我仍然有很多代码只处理我的仪表板的另一半:会计(费用、支出等),它使我的用户模型变得混乱。你对此有什么建议吗?
  • 如果它们只在仪表板中使用,请将它们移到此处。如果他们正在处理用户的数据,我认为离开那里可能是有意义的。如果仅在仪表板中使用,我会提取到仪表板对象。
  • 我现在为仪表板上的三个小部件中的每一个创建了一个“小部件”类(它们有点复杂,所以我认为拆分代码会很好)。前三个方法 (last_month_...) 现在从模型移至 UsageWidget 类。这已经看起来好多了。但是我仍然觉得处理用户使用/费用的其余方法不属于用户类。他们都没有调用任何方法或使用来自用户的任何属性期望相关联的 Dinner_clubs 来计算总价。有什么重构的建议吗?
  • 当然,创建一个 UserDashboard 类来接收用户并添加这些方法。
猜你喜欢
  • 2019-05-14
  • 1970-01-01
  • 2011-10-09
  • 1970-01-01
  • 2011-04-26
  • 1970-01-01
  • 1970-01-01
  • 2017-11-17
  • 1970-01-01
相关资源
最近更新 更多