如何在简单的Ruby购物车中提供折扣?

如何在简单的Ruby购物车中提供折扣?,ruby,Ruby,我正在尝试制作一个非常简单的Ruby购物车,如果用户购买某些商品组合,我需要能够提供折扣。这些在@costs中表示-如果bulk为true,则用户购买:bulk\u num商品可获得折扣(即:bulk\u price)。我已经让它做了基本的收费,但现在我需要在某些情况下减去折扣。以下是我目前掌握的情况: class Cart attr_accessor :total, :costs, :item_array, :subtotal def initialize

我正在尝试制作一个非常简单的Ruby购物车,如果用户购买某些商品组合,我需要能够提供折扣。这些在@costs中表示-如果bulk为true,则用户购买:bulk\u num商品可获得折扣(即:bulk\u price)。我已经让它做了基本的收费,但现在我需要在某些情况下减去折扣。以下是我目前掌握的情况:

    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
class购物车
属性存取器:总计,:成本,:项目数组,:小计
def初始化
@项_数组=[]
@小计=0
@成本=[{“A”=>{:价格=>2,:批量=>true,:批量数量=>4,:批量价格=>7},{“B”=>{:价格=>12,:批量=>false},{“C”=>{:价格=>1.25,:批量=>true,:批量数量=>6,:批量价格=>6},{“D”=>{:价格=>0.15,:批量=>false}]
结束
def扫描(*项)
项目。每个do |项目|
@item_数组有几件事:

  • 适当地缩进代码,从长远来看,这将使代码更容易
  • attr\u访问器
    中删除
    :total
    ,不需要它,生成的
    total
    方法将被稍后定义的方法覆盖
  • 考虑使每个项目成为一个了解其自身成本的对象,而不是在
    @costs
    中查找每个项目的成本。从概念上讲,“购物车”跟踪商店中所有商品的所有价格是没有意义的
  • 使您的
    总计
    方法发挥作用。不要费心从
    @subtotal
    中减法——如果多次调用
    total
    ,将导致问题
  • 实际上,如果您在需要时重新计算,
    小计也会更好:

    def subtotal
      @item_array.reduce(0) { |sum,item| sum + (@costs[item][:price] || 0) }
    end
    
现在您可能不太清楚,但是像这样“按功能”编写代码可以更容易地避免bug。如果值的计算非常昂贵,并且需要多次,则可以缓存这些值,但在这种情况下,不需要缓存

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

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

由于你的问题涉及到一个练习,我决定将其稍作改动,提出一些你可能会觉得有用的观点。请注意:

  • 我将
    scan
    重命名为
    checkout
    ,以免将前者与
  • 以散列的形式为订购的每个项目提供订购数量,散列传递给
    checkout
    方法
  • 我将
    :bulk\u price
    更改为适用于
    :bulk
    为真且订购数量至少为
    :bulk\u num
    的单价
  • 我将
    @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

不清楚你的问题是什么。我不知道如何考虑折扣。某些项目是打折的-例如,如果你买了4个项目,A可以享受1美元的折扣,但是B从来没有打折。我确信这个线程将关闭,因为你似乎没有什么问题,除了“你能帮我修复我的代码吗?”,但在我看来,项目应该具有“折扣”属性。当你计算总数时,你会检查一件物品是否有折扣,然后应用它。谢谢!对不起,像这样的任务我是个新手。好啊我将尝试实现其中的一些功能,以确保我了解Ruby的大多数很棒的函数式编程方法都来自该模块。在学习诸如each、map、reduce和find_all等方法时,一定要查看相关文档。另外,请注意,String、Array、Hash和其他常见Ruby类包括Enumerable的方法。