当前位置:  开发笔记 > 后端 > 正文

使用元编程重构包含"双管道"和"实例变量"的代码

如何解决《使用元编程重构包含"双管道"和"实例变量"的代码》经验,为你挑选了1个好方法。

我有两种方法:

def ios_ids
  @ios_ids ||= Array(GcmToken.find_by(users_id: "#{@event.user_id}", os_type: 'ios', alive: true).try(:reg_id))       
end

def android_ids
  @android_ids ||= Array(GcmToken.find_by(users_id: "#{@event.user_id}", os_type: 'android', alive: true).try(:reg_id)) 
end

我想把它们折射成下面的东西

%w(android ios).each do |os_type|
  define_method(:"#{os_type}_ids") { "@#{os_type}_ids" ||= Array(GcmToken.find_by(users_id: "#{@event.user_id}", os_type: os_type, alive: true).try(:reg_id))}
end

但它不起作用

有人有任何答案或更好的解决方案?



1> tadman..:

使用这种元编程实在是非常严厉,尤其是在操作像这样的实例变量时.通常当你沿着这条路走下去时,这是因为你有很多需要整理的情况.

让我们以较小的步骤解决这个问题:

def ios_ids
  @ios_ids ||= Array(GcmToken.find_by(users_id: "#{@event.user_id}", os_type: 'ios', alive: true).try(:reg_id))       
end

这里发生了一些非常奇怪的事情,比如"#{x}"反模式,它引用了一个几乎总是毫无意义的单个值.如果您绝对需要字符串,请使用.to_s相关值.

这也会加载模型并尝试从中获取属性.那太浪费了.它还使用Array(...)很少使用的不规则符号将其打包.[ ... ]是优选的.

所以清理一下你会得到:

def ios_ids
  @ios_ids ||= GcmToken.where(
    users_id: @event.user_id,
    os_type: 'ios',
    alive: true
  ).pluck(:reg_id)
end

这让它失去了很多.现在它只是reg_id从该GcmToken模型中获取所有相关值.如果你有一个User has_many :gcm_tokensEvent belongs_to :user,这应该是给定数据的情况,那么你可以更清理它:

def ios_ids
  @ios_ids ||= @event.user.gcm_tokens.where(
    os_type: 'ios',
    alive: true
  ).pluck(:reg_id)
end

您可以通过简单的scope声明进行更多清理:

scope :alive_for_os_type, -> (os_type) {
  where(os_type: os_type, alive: true)
}

然后它变得更小:

def ios_ids
  @ios_ids ||= @event.user.gcm_tokens.alive_for_os_type('ios').pluck(:reg_id)
end

这变得非常小.在这一点上减少这个define_method是过度杀死,但如果你真的想要,那么这样做:

OS_TYPES = %w[ android ios ].freeze

OS_TYPES.each do |os_type|
  method_name = "#{os_type}_ids".to_sym
  instance_var = "@#{method_name}".to_sym

  define_method(method_name) do
    instance_variable_get(instance_var) or
      instance_variable_set(
        instance_var,
        @event.user.gcm_tokens.where(
          os_type: 'ios',
          alive: true
        ).pluck(:reg_id)
      )
  end
end

这最终会变得更加混乱和代码,而不仅仅是将每个实现逐渐简化为更小的形式.如果你有几十种类型,你可能想要这样做,但老实说,这是怎么回事:

def platform_ids(os_type)
  @platform_ids ||= { }

  @platform_ids[os_type] ||= @event.user.gcm_tokens.alive_for_os_type(os_type).pluck(:reg_id)
end

一种可以处理N种类型的方法,您只需指定哪一种.有时特殊用途的方法不值得大惊小怪.

推荐阅读
pan2502851807
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有