所以我正在制作类似于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美元。
有没有人知道我犯了什么错误?我已经过了很多年了,无法解决它。任何帮助将不胜感激!
答案 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))