我在遗留系统中有一个模型,看起来像这样:
class Prize < ActiveRecord::Base
def win
# do a bunch of things
end
end
我们从一个奖项开始,但就像其他任何东西一样,我们正在处理的奖项类型开始扩大。 所以现在def win正在做一大堆案例/切换来决定奖品类型。
出于这个原因,我决定这样做:
class DailyPrize < Prize
def win
#do only daily prize stuff, no type checking.
end
end
在我们将其发送给QA之前,该代码已经过审查,现在我被要求使用组合(mixin)而不是子类来执行此操作。 我想不出一个干净的方法来做到这一点。
遗留代码库在很多地方都在做以下事情,我不想到处改变东西:
奖品 = 奖品.新品赢奖
那么,我的问题如何使用构图来实现这一目标?
这是我通过组合而不是继承替换您的代码所理解的。
class Prize < ActiveRecord::Base
def prize
@prize ||= PrizeFactory.build(self)
end
def win
prize.win
end
end
class PrizeFactory
def self.build(prize)
if prize.daily?
DailyPrize.new(prize)
# other condition to build specific prize
end
end
end
class DailyPrize
def initialize(prize)
@prize = prize
end
def win
#do only daily prize stuff
#access @prize to get @prize attribute
#if you use it, you have coupling (see below)
end
end
问题是,这可能并不比你的实现更好,它实际上取决于你在域逻辑方面实现的目标。
对于组合,一个目标是减少对象之间的耦合,如果您在DailyPrice
win
方法中调用大量@prize
对象方法,则这两个类之间存在紧密耦合,您可能会失去组合的好处。
我能想到的一种方法是将特定的奖品作为模块,例如
module DailyPrize
def specific_method_1
end
def specific_method_2
end
end
。然后将奖品类设置为:
class Prize
def win
# do something in common
specific_method_1
# do something in common
specific_method_2
# ...
end
end
然后,您可以根据需要混合模块,例如在实例化类时
def initialize (prize_type)
# mixin the appropriate module
end