Ruby 使用策略模式重构。红宝石色

Ruby 使用策略模式重构。红宝石色,ruby,design-patterns,activerecord,refactoring,strategy-pattern,Ruby,Design Patterns,Activerecord,Refactoring,Strategy Pattern,小心!在下面的示例中,使用模式可能有些过分。。。然而,如果我把它扩展到计算流派,计算给定乐队的成员,计算粉丝数量,计算播放场地的数量,计算出售唱片的数量,计算特定歌曲的下载数量等等。。。似乎有很多东西要数 目标: 创建一个新函数,根据输入选择正确的计数函数 示例: class Genre < ActiveRecord::Base has_many :songs has_many :artists, through: :songs def song_count se

小心!在下面的示例中,使用模式可能有些过分。。。然而,如果我把它扩展到计算流派,计算给定乐队的成员,计算粉丝数量,计算播放场地的数量,计算出售唱片的数量,计算特定歌曲的下载数量等等。。。似乎有很多东西要数

目标

创建一个新函数,根据输入选择正确的计数函数

示例



class Genre < ActiveRecord::Base
  has_many :songs
  has_many :artists, through: :songs

  def song_count
    self.songs.length
  end

  def artist_count
    self.artists.length
  end

end

类类型

另外,如果你对这个问题也很好奇,你可能会发现另一个问题(不幸的是用C#回答)作为补充上下文很有帮助

在Ruby中,您可以使用(可选)块(假设它仍然未使用)非常轻松地实现策略模式

如果您需要更频繁地重复使用某些策略,您可以将它们保存在常量或变量中:

LENGTH_STRATEGY = ->(collection) { collection.length }

genre.artist_count(&LENGTH_STRATEGY)
或者为它们创建一个特定的类,如果它们更复杂(目前过于复杂):

类集合策略
将类作为块参数提供时调用def self.to#u proc
->(收集){new(收集).call}
结束
属性读取器:集合
def初始化(收集)
@集合=集合
结束
结束
类长度策略<集合策略
def呼叫
集合长度
结束
结束
类型。艺术家数量(长度策略)

你似乎忘记问问题了?在这个特殊的例子中,我建议一个。那就
hiphop=Genre.new;hiphop.songs.count
几乎任何事情都是可能的,但你要问的更多的是元编程,而不是策略模式。你认为这个用法是什么?类似于:
流派。计数(:歌曲)
?或者简单地
genre.count
,它希望通过标准输入提供集合。请注意,在最后一个示例中,Rails服务器的使用非常复杂,因为只有服务器主机可以提供标准输入。这非常有用!你帮我澄清了我的意图:例如,“你想数数什么?”被打印到屏幕上。。。用户可以输入“Korsakov的歌曲”。。。正则表达式将确定Korsakov是对象,程序将“知道”歌曲是集合。或者“Korsakov演唱会”,或者“Korsakov的学生”,也许我们有一个功能,可以识别关键词:歌曲、音乐会、学生,还有艺术家(比如| |=),然后使用单一功能/魔术方法作为策略。不管怎样,谢谢你的反馈!类似于计算对象中的任何东西(对象,对象中的任何东西)——还有我的道歉。我觉得作为一个新手,一半的问题在于不能清楚地表达你的意思。看到你的答案很好,因为这有助于我更好地了解一些概念的起点和终点。@Adamweisman今天晚些时候我将扩展答案(并删除此回复)。我目前没有时间完全回答您的补充要求。不过我还有一个问题。由于您继承自
ActiveRecord::Base
,我假设这涉及Rails应用程序,用户必须通过web请求提供输入,而不是标准输入。@3limini4t0r非常感谢您的帮助,但请不要担心写出来。。。没有更大的应用程序。我用这个例子来探索一个机械师。我很感谢你的帮助,因为我现在意识到我必须深入元编程!
genre = Genre.last
genre.song_count # get the song_count using the default #size strategy
# or provide a custom stratigy
genre.song_count { |songs| songs.count } # get the song_count using #count
genre.song_count { |songs| songs.length } # get the song_count using #length
LENGTH_STRATEGY = ->(collection) { collection.length }

genre.artist_count(&LENGTH_STRATEGY)
class CollectionStrategy
  def self.to_proc # called when providing the class as a block argument
    ->(collection) { new(collection).call }
  end

  attr_reader :collection

  def initialize(collection)
    @collection = collection
  end
end

class LengthStrategy < CollectionStrategy
  def call
    collection.length
  end
end

genre.artist_count(&LengthStrategy)