珍珠翡翠白玉汤

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

.Net PetShop 3.0中购物车总价计算的bug

  当在购物车页面(ShoppingCart.aspx)中,更改了购物车中某一个商品的数量(Quantity栏)后,点击Update按钮来更新购物车的总价(Total),但是购物车的总价并没有被更新,这是一个bug。

  在业务逻辑层(BLL)中,购物车由Cart类表示,而购物车中每个商品记录则由Mode模块的CartItemInfo类来表示。CartItemInfo类的Price、Quantity和Subtotal属性表示购物车中每个商品记录的单价、数量和价格小计(Subtotal=Price*Quantity),而Cart类的Total属性表示购物车的总价。购物车的总价应该是购物车中每个商品记录的价格小计的总和。


  在什么时候计算购物车的总价,有两种可选的方式:
1)在向购物车中添加商品记录、删除商品记录和修改购物车中某商品记录的数量时,修改购物车总价
2)在要读取购物车总价时,遍历购物车中每个商品记录来计算购物车总价
  从类的设计角度来讲,第二种方式明显要好于第一种方式。因为,第一种方式中,计算总价的逻辑被分散到多个地方(Cart类的Add、Remove、RemoveAt方法和UI层的Update按钮的事件处理方法)来实现。第二种方式中,只需要在Cart类的Total属性的代码中来实现计算总价的逻辑。
  令人不解的是,.net PetShop使用的是第一种方式,在Cart类的Add、Remove、RemoveAt方法编写了计算总价的代码,但是在Update按钮的事件处理方法(PetShop.Web.ShoppingCart类的CommandClicked方法)中却没有修改购物车总价的代码,这就是Bug的所在。
  CommandClicked方法的代码如下:
---------------------------------------------------------
  /// <summary>
  /// Function to control user clicking on a button on the page
  /// 处理Remove和Update按钮的事件
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  protected void CommandClicked(object sender, RepeaterCommandEventArgs e)
  {
   // Check for update button
   if (e.CommandName == CMD_UPDATE)
   {
    TextBox txt;
    int qty;
    int index;

    // Go through each item on the page
    // 遍历购物车中每一条商品记录,如果其数量在页面上被修改了,则更新之
    // cart(ViewStatePager控件)和myCart(Cart对象)保持一致
    for (int i = 0, j = cart.Items.Count; i < j; i++){

     // lookup the control
     txt = (TextBox)cart.Items[i].FindControl(ID_TXT);

     try
     {
      // 得到商品记录的数量
      qty = int.Parse(txt.Text);
      // 得到商品记录在购物车中的下标
      index = cart.CurrentPageIndex * cart.PageSize + i;
      
      // If the new qty is zero, remove the item from the cart
      if (qty <= 0)
       myCart.RemoveAt(index);     
      // Update the item with the new quantity
      else
       //在购物车对象中更新指定商品记录的数量
       //这时,购物车的总价发生了变化,但这里没有作相应的处理,是一个bug
       myCart[index].Quantity = qty;
     }
     catch
     {}    //忽略所有异常
    }   
   }
   else
    // otherwise the command is to remove the an item
    myCart.Remove((string)e.CommandArgument);

   // Refresh the contents of the cart page
   Refresh();

   // Update the page count if required
   int pageCount = (myCart.Count - 1) / cart.PageSize;
   cart.SetPage(Math.Min(cart.CurrentPageIndex, pageCount));
  }
-------------------------------------------------------

  相应的,可以用上述的两种方式来修补这个bug。第一种方式只需要在UI层的ShoppingCart类的CommandClicked方法中加上修改购物车总价的代码。第二种方式,需要删除Cart类的Add、Remove、RemoveAt方法中相关的代码,然后重新编写Cart类的Total属性的实现代码。
  这里采用第二种方式,Cart的代码如下:
-----------------------------------------------------
using System;
using System.Collections;

//References to PetShop specific libraries
//PetShop busines entity library
using PetShop.Model;

namespace PetShop.BLL {
 
 /// <summary>
 /// An object to represent a customer's shopping cart
 /// 购物车类
 /// </summary>
 [Serializable]
 public class Cart : IEnumerable {

  /// <summary>
  /// Internal storage for a cart
  /// 数组列表中保存的是CartItemInfo对象实例
  /// </summary>
  private ArrayList _items = new ArrayList();
  //Fixbug bug001: 修改了属性Total,下面的一条语句就不需要了(被注释掉)
//  private decimal _total=0;

  /// <summary>
  /// Returns an enumerator for the cart items in a cart
  /// </summary>
  /// <returns></returns>
  public IEnumerator GetEnumerator() {
   return _items.GetEnumerator();
  }

  // Properties  
  public decimal Total
  {
   //Fixbug bug001: Total属性应该是只读的,其值应该是自动计算的
//   get { return _total; }
//   set { _total = value; }
   //Fixbug bug001: 重写的代码
     get{
    Decimal total = 0;
    foreach(CartItemInfo cartItem in _items)
    {
     total += cartItem.Subtotal;
    }
    return total;
   }
  }

  /// <summary>
  /// Returns number of items in cart
  /// 返回购物车中商品项的数目
  /// </summary>
  public int Count {
   get { return _items.Count; }
  }

  /// <summary>
  /// Return CartItem representation of object at a given address
  /// 索引器。获取购物车中任一商品项的信息
  /// </summary>
  ///
  public CartItemInfo this[int index] {
   get { return (CartItemInfo)_items[index]; }
  }

  /// <summary>
  /// Add an item to the cart
  /// 添加一个商品项到购物车
  /// </summary>
  /// <param name="ItemId">ItemId of item to add</param>
  public void Add(string ItemId)
  {
   foreach (CartItemInfo cartItem in _items) //如果商品项已经存在于购物车中
   {
    if (ItemId == cartItem.ItemId) {
     cartItem.Quantity++; // 该商品项的个数加一
     // 判定该商品项是否还有库存
     cartItem.InStock = (GetInStock(ItemId) - cartItem.Quantity) >= 0 ? true : false;
     //Fixbug bug001: 修改了属性Total,下面的一条语句就不需要了(被注释掉)
//     _total = _total+(cartItem.Price*cartItem.Quantity); //修改购物车中商品的总价
     return;
    }
   }

   Item item = new Item();
   ItemInfo data = item.GetItem(ItemId);
   CartItemInfo newItem = new  CartItemInfo(ItemId,data.Name,(data.Quantity >= 1),1,(decimal)data.Price);

   _items.Add(newItem);
   //Fixbug bug001: 修改了属性Total,下面的一条语句就不需要了(被注释掉)
//   _total = _total+(data.Price);
  }

  /// <summary>
  /// Remove item from the cart based on itemId
  /// 从购物车中移除一个商品项
  /// </summary>
  /// <param name="itemId">ItemId of item to remove</param>
  public void Remove(string itemId) {
   foreach (CartItemInfo item in _items) {
    if (itemId == item.ItemId)  //找到指定的商品项id
    {
     _items.Remove(item);
     //Fixbug bug001: 修改了属性Total,下面的一条语句就不需要了(被注释掉)
//     _total = _total-(item.Price*item.Quantity); //修改总价
     return;
    }
   }
  }

  /// <summary>
  /// Removes item from cart at specific index
  /// 从购物车中移除一个商品项(指定索引)
  /// </summary>
  /// <param name="index">Element number of item to remove</param>
  public void RemoveAt(int index)
  {
   CartItemInfo item = (CartItemInfo)_items[index];
   //Fixbug bug001: 修改了属性Total,下面的一条语句就不需要了(被注释掉)
//   _total = _total-(item.Price*item.Quantity);
   _items.RemoveAt(index);   
  }

  /// <summary>
  /// Returs internal array list of cart items
  /// </summary>
  /// <returns></returns>
  public ArrayList GetCartItems() {
   return _items;
  }

  /// <summary>
  /// Method to convert internal array of cart items to order line items
  /// 将购物车中的商品项信息转换为订单明细信息
  /// </summary>
  /// <returns>New array list of order line items</returns>
  public ArrayList GetOrderLineItems() {

   ArrayList orderLineItems = new ArrayList();

   int lineNum = 1;

   foreach (CartItemInfo item in _items) {
    // 购物车中每一个商品项就生成一条订单明细行
    LineItemInfo lineItem = new LineItemInfo(item.ItemId,item.Name,lineNum,item.Quantity,item.Price);
    orderLineItems.Add(lineItem);
    lineNum++;
   }

   return orderLineItems;
  }

  
  /// <summary>
  /// Internal method to get the stock level of an item
  /// 获得指定商品项的库存数
  /// </summary>
  /// <param name="ItemId">Unique identifier of item to get stock level of</param>
  /// <returns></returns>
  private int GetInStock(string ItemId)
  {
   Inventory inventory = new Inventory();
   return inventory.CurrentQuantityInStock(ItemId);
  }
 }
}

posted on 2007-03-08 15:18  zqf620  阅读(4553)  评论(4编辑  收藏  举报