结账系统给出了奇怪的结果

时间:2015-06-18 01:56:34

标签: ruby

所以我正在制作类似于this的结帐系统。但是,我有3个项目(A,B和C分别为3.11美元,5.00美元和11.23美元)。

条件是,如果购买3个或更多单位,则商品A具有买一送一优惠,商品B减少到4.50美元。测试代码时会出现问题。

我已经编写了以下代码来解决这个问题:

class PriceDiscount  # Applies price discounts for a specific number of items

# Initial method with item price and item quantity parameters
  def initialize(itemprice, quantity)
    @itemprice = itemprice
    @quantity = quantity
  end

# "calculate_for" method which calculates the discount for the specific number of items
  def calculate_for(quantity)
    (quantity / @quantity).floor * @itemprice
  end

end


class PricePolicy  # Calculates the price for a certain quantity of items after discounts

# Initial method with the original price and discounts as the paremeters
  def initialize(orgprice, *discounts)
    @orgprice = orgprice
    @discounts = discounts
  end

# Calculates the discounted price of a number of items
  def price_for(quantity)
    quantity * @orgprice - discount_for(quantity)
  end

# Calculates the discount which is given for a number of items
  def discount_for(quantity)
    @discounts.inject(0) do |mem, discount|
      mem + discount.calculate_for(quantity)
    end
  end
end


# Rule list set up for great flexibility as each rule is specified in one line
RULES = {
  'A' => PricePolicy.new(3.11, PriceDiscount.new(3.11, 2)), 
  'B' => PricePolicy.new(5.00, PriceDiscount.new(4.50, 2)),
  'C' => PricePolicy.new(11.23),
}


class Checkout # Checkout class which applies the rules to each item that is scanned

# Initial method which has the rules and items as its parameters
  def initialize(rules)
    @rules = rules
    @items = Hash.new
  end

# Method to set up the array in which scanned items are stored
  def scan(item)
    @items[item] ||= 0
    @items[item] += 1
  end

# Method which totals the price of the scanned items
  def total
    @items.inject(0) do |mem, (item, quantity)|
      mem + price_for(item, quantity)
    end
  end

  private 
  def price_for(item, quantity)
    if rule_for(item)
      rule_for(item).price_for(quantity)
    else
      raise "Invalid item '#{item}'"
    end
  end

  def rule_for(item)
    @rules[item]
  end
end

这是测试人员:

require 'test/unit'
require_relative './CheckoutSystem.rb'

class TestPrice < Test::Unit::TestCase

  def price(goods)
    co = Checkout.new(RULES)
    goods.split(//).each { |item| co.scan(item) }
    co.total
  end


  def test_totals

    # Scenario 1 with basket: A, B, A, A, C
    assert_equal(22.45, price("ABAAC").round(2))

    # Scenario 2 with basket: A, A
    assert_equal(3.11, price("AA").round(2))

    # Scenario 3 with basket: B, B, A, B
    assert_equal(16.61, price("BBAB").round(2))
  end

end

场景1和2给出正确的值。但是,方案3给出了13.11美元的价值,实际上它应该是16.61美元。

有没有人知道我犯了什么错误?我已经过了很多年了,无法解决它。任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:1)

要更改程序以传递测试用例,您必须更改:

'B' => PricePolicy.new(5.00, PriceDiscount.new(4.50, 2)),

'B' => PricePolicy.new(5.00, PriceDiscount.new(1.50, 3)),

这样,当用户购买3&#39; B&#39;物品,他们将获得1.5的折扣,这意味着3个项目的总价格将从15变为13.5(每个4.50。)

请注意,在这种情况下,如果用户购买4&#39; B&#39;物品,他们将获得前3个折扣,但第四个项目没有折扣。

要解决问题,以便在3个或更多项目中正常使用&#39;如果购买,则必须更改discount.calculate_for方法。这是因为&#39; A&#39;和&#39; B&#39;商品会以不同的方式计算折扣:

一个简单的实现方法是定义一个&#39;类型&#39;对于每种情况。在下面的示例中,空类型仅代表&x; x或更多项目&#39;情况,bogo类型代表购买x并获得平价折扣&#39;情况。

class PriceDiscount
  def initialize(itemprice, quantity, type = nil)
    @itemprice = itemprice
    @quantity = quantity
    @type = type
    raise "Invalid type '#{type}'" if @type != 'bogo' && @type != nil
  end

  def calculate_for(quantity)
    if (@type == 'bogo')
      (quantity / @quantity) * @itemprice
    elsif quantity >= @quantity
      (quantity.to_f / @quantity) * @itemprice
    else
      0
    end
  end
end

规则将更新如下:

RULES = {
  'A' => PricePolicy.new(3.11, PriceDiscount.new(3.11, 2, 'bogo')), 
  'B' => PricePolicy.new(5.00, PriceDiscount.new(1.50, 3)),
  'C' => PricePolicy.new(11.23),
}

bogo项目将使用与之前相同的计算,这意味着AA有1个折扣,AAA有1个折扣,AAAA有2个折扣。 &#39; x或更多项目&#39;将首先检查物品数量是否达到阈值,如果是,则将折扣率应用于这些物品中的每一个。 (在这种情况下,BBB将应用1.50的指定折扣.BBBB将应用折扣的修改版本 - > 2.00,以匹配4个项目。)

同样,你可以放弃&#39; .floor&#39;整理方法 - &gt;它会在转换时自动落地。要获得非整数结果,您可以看到我已将第二个计算中的一个值转换为浮点数。

尝试使用这些特定于更改的测试运行这些更改:

assert_equal(13.11, price("BBA").round(2))
assert_equal(21.11, price("BBBBA").round(2))
assert_equal(22.45, price("AAAABC").round(2))
assert_equal(25.56, price("AAAAABC").round(2))