使用策略模式进行重构。在 Ruby
Refactor with Strategy Pattern. In Ruby
注意!在下面的示例中,使用模式可能有点矫枉过正......但是,如果我将其扩展到计算流派,计算给定乐队中的成员,计算粉丝数量,计算播放场地的数量,计算销售的唱片,计算特定歌曲的下载次数等...似乎有很多东西要计算。
目标:
创建一个根据输入选择正确计数函数的新函数。
例子:
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
P.S。如果您也对这个问题感到好奇,您可能会发现这个其他问题(不幸的是在 C# 中回答)作为补充上下文很有帮助。 Strategy or Command pattern? ...
在 Ruby 中,您可以使用(可选)块(假设它仍未使用)很容易地实现策略模式。
class Genre < ActiveRecord::Base
has_many :songs
has_many :artists, through: :songs
def song_count(&strategy)
count_using_strategy(songs, &strategy)
end
def artist_count(&strategy)
count_using_strategy(artists, &strategy)
end
private
def count_using_strategy(collection, &strategy)
strategy ||= ->(collection) { collection.size }
strategy.call(collection)
end
end
以上代码默认使用size
策略。如果您想在特定场景中使用特定策略,您只需在调用时提供该策略即可。
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:
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)
注意!在下面的示例中,使用模式可能有点矫枉过正......但是,如果我将其扩展到计算流派,计算给定乐队中的成员,计算粉丝数量,计算播放场地的数量,计算销售的唱片,计算特定歌曲的下载次数等...似乎有很多东西要计算。
目标:
创建一个根据输入选择正确计数函数的新函数。
例子:
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
P.S。如果您也对这个问题感到好奇,您可能会发现这个其他问题(不幸的是在 C# 中回答)作为补充上下文很有帮助。 Strategy or Command pattern? ...
在 Ruby 中,您可以使用(可选)块(假设它仍未使用)很容易地实现策略模式。
class Genre < ActiveRecord::Base
has_many :songs
has_many :artists, through: :songs
def song_count(&strategy)
count_using_strategy(songs, &strategy)
end
def artist_count(&strategy)
count_using_strategy(artists, &strategy)
end
private
def count_using_strategy(collection, &strategy)
strategy ||= ->(collection) { collection.size }
strategy.call(collection)
end
end
以上代码默认使用size
策略。如果您想在特定场景中使用特定策略,您只需在调用时提供该策略即可。
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:
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)