3

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

 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)而不是子类化来执行此操作。我想不出一个干净的方法来做到这一点。

遗留代码库在很多地方执行以下操作,我不想到处更改东西:

奖品 = Prize.new Prize.win

那么,我的问题是如何使用组合来实现这一点?

4

2 回答 2

4

这是我通过组合而不是继承替换您的代码的理解。

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

问题是,这可能并不比您的实现更好,这实际上取决于您在领域逻辑方面取得的成就。

使用组合,一个目标是减少对象之间的耦合,如果你在方法中调用了很多@prize对象方法DailyPrice win,那么这两个类之间的耦合很紧密,你可能会失去组合的好处。

于 2012-11-26T20:46:09.527 回答
0

我能想到的一种方法是将特定奖品作为模块,例如

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
于 2012-11-26T19:11:44.777 回答