如何在简单的Ruby购物车中给予折扣?

时间:2013-12-17 00:00:10

标签: ruby

我正在尝试制作一个非常简单的Ruby购物车,如果用户购买某些商品组合,我需要能够提供折扣。这些在@costs中表示 - 如果批量为true,则用户获得折扣(of bulk_price)以进行购买:bulk_num货物。我已经得到了基本费用,但现在我需要在某些情况下减去折扣。这是我到目前为止所做的:

    class Cart
     attr_accessor :total, :costs, :item_array, :subtotal

     def initialize
      @item_array=[]
      @subtotal=0
      @costs= [{"A"=>{:price=>2, :bulk=>true, :bulk_num=>4, :bulk_price=>7}}, {"B"=>{:price=>12, :bulk=> false}},{"C"=>{:price=>1.25,:bulk=>true, :bulk_num=>6, :bulk_price=>6}}, {"D"=>{:price=>0.15, :bulk=>false}}]
     end



    def scan(*items)
     items.each do |item|
     @item_array<<item
     @costs.each do |cost|
     if cost.has_key?(item)
      @subtotal+=cost[item][:price]
     end
   end
   @subtotal
 end
end


 def total

 end

end

现在,我已经创建了一个数组来跟踪购买的项目,理想情况下我希望让总函数检查数组,并在需要时从小计中减去。也许我只是盯着这个太久了,但我很难搞清楚。有人可以帮忙吗?

2 个答案:

答案 0 :(得分:2)

一些事情:

  • 正确缩进代码,从长远来看,这将使您更容易。
  • :total移除attr_accessor,不需要它,生成的total方法将被您稍后定义的方法覆盖。
  • 考虑让每个项目成为一个知道自己成本的对象,而不是在@costs中查找每个项目的成本。从概念上讲,“购物车”跟踪商店中所有商品的所有价格是没有意义的。
  • 让您的total方法正常运行。不要费心从@subtotal中减去 - 如果多次调用total,则会导致问题。
  • 实际上,如果您在需要时重新计算,subtotal也会更好:

    def subtotal
      @item_array.reduce(0) { |sum,item| sum + (@costs[item][:price] || 0) }
    end
    

现在对你来说可能并不明显,但是像这样“功能性地”编写代码可以更容易地避免错误。您可以缓存值,如果它们的计算成本非常高,并且需要不止一次,但在这种情况下不需要。

  • 对于total,您可以执行以下操作:

    def total
      result = self.subtotal
      # check which discounts apply and subtract from 'result'
      result
    end
    

答案 1 :(得分:1)

由于你的问题涉及练习,我决定稍微改变一下,以便提出一些你可能会觉得有用的观点。几点说明:

  • 我将scan重命名为checkout,以免前者与String#scan
  • 混淆
  • 以传递给checkout方法的哈希形式为每个订购的商品指定订单数量;
  • 如果:bulk_price为真且订购的数量至少为:bulk,我将:bulk_num更改为适用的单价。
  • 我将@costs更改为哈希,因为您需要访问项目名称,这些项目现在是密钥。
  • 由于两个原因,我将@costs移到课堂外。首先,这些数据可能会发生变化,因此在课堂定义中确实不应该硬连线。其次,如果您希望不同的类实例使用不同的@costs,那么这样做可以提供灵活性。在创建新的类实例时,您会看到我选择将该哈希作为参数传递。
  • 我删除了所有访问者。
  • 如果您输入的项目名称不是@costs中的关键字,则会引发异常。

这是我采取的方法:

class Cart
  def initialize(costs)
    @costs= costs
  end
  def checkout(items)
    purchases = {}
    items.each do |(item, qty)|
      cost = @costs[item]
      raise ArgumentError, "Item '#{item}' not in @costs array" \
        if cost == nil
      if cost[:bulk] && qty >= cost[:bulk_num]
        tot_cost = qty.to_f * cost[:bulk_price]
        discount = qty.to_f * (cost[:price] - cost[:bulk_price])
      else
        tot_cost = qty.to_f * cost[:price]
        discount = 0.0
      end
      purchases[item] = {qty: qty, tot_cost: tot_cost, discount: discount}
    end
    purchases
  end
  def tot_cost(purchases)
    purchases.values.reduce(0) {|tot, h| tot + h[:tot_cost]}
  end
  def tot_discount(purchases)
    purchases.values.reduce(0) {|tot, h| tot + h[:discount]}
  end
end 

costs = {"A"=>{price:    2, bulk: true, bulk_num: 4, bulk_price: 1.75},
         "B"=>{price:   12, bulk: false                              },
         "C"=>{price: 1.25, bulk: true, bulk_num: 6, bulk_price: 1.00},
         "D"=>{price: 0.15, bulk: false                              }}
cart = Cart.new(costs)

purchases = cart.checkout({"A"=>6, "B"=>7, "C"=>4}) # item => quantity purchased
p purchases # => {"A"=>{:qty=>6, :tot_cost=>10.5, :discount=>1.5},
            # =>  "B"=>{:qty=>7, :tot_cost=>84.0, :discount=>0.0},
            # =>  "C"=>{:qty=>4, :tot_cost=>5.0,  :discount=>0.0}}

p cart.tot_cost(purchases)     # => 99.5
p cart.tot_discount(purchases) # =>  1.5