在轨道中将继承转换为组合



我在遗留系统中有一个模型,看起来像这样:

 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

最新更新