C# 我应该将费用/折扣列表合并到订单类中还是将其作为项目行
我没有其他开发人员可以征求意见或“你怎么想-我在想这个”,所以如果你有时间,请阅读并让我知道你的想法 显示比描述更容易,但该应用程序本质上类似于一个销售点应用程序,有三个主要部分:项目、订单项目和订单 item类是来自数据存储的数据C# 我应该将费用/折扣列表合并到订单类中还是将其作为项目行,c#,oop,C#,Oop,我没有其他开发人员可以征求意见或“你怎么想-我在想这个”,所以如果你有时间,请阅读并让我知道你的想法 显示比描述更容易,但该应用程序本质上类似于一个销售点应用程序,有三个主要部分:项目、订单项目和订单 item类是来自数据存储的数据 public class Item : IComparable<OrderItem>, IEquatable<OrderItem> { public Int32 ID { get; set; } public Str
public class Item
: IComparable<OrderItem>, IEquatable<OrderItem>
{
public Int32 ID { get; set; }
public String Description { get; set; }
public decimal Cost { get; set; }
public Item(Int32 id, String description, decimal cost)
{
ID = id;
Description = description;
Cost = cost;
}
// Extraneous Detail Omitted
}
我喜欢它,这很有意义,Order继承的基类遍历列表中的项目,计算适当的税,并允许其他Order类型文档(其中有2个)从基类继承,该基类计算所有这些,而无需重新实现任何内容。如果订单类型文档没有折扣,只需不添加价值为-$value的OrderItem即可
我遇到的唯一问题是显示这些数据。该表单有一个网格,其中应显示销售项目(即非费用/折扣)。同样,也有用于支付某些费用和某些折扣的文本框。我非常希望将这些ui元素数据绑定到这个类中的字段,这样对用户(和我)来说就更容易了
我的想法
有2个接口:IHasFees、iHasFellows和Order实现它们;两者都将有一个单一的成员名单。这样,我只能访问销售项目、费用和折扣(如果需要,还可以将它们绑定到控件)
我不喜欢的是:
-现在我为这个类提供了3种不同的添加/删除方法(AddItem/AddFee/AddDiscount/remove…)
-我正在复制(三倍?)功能,因为它们都只是相同类型项目的列表,只是每个列表都有不同的含义
我走对了吗?我怀疑这对大多数人来说是一个已解决的问题(考虑到这种类型的软件非常常见)。一个选项是向OrderItem添加ItemType属性
enum ItemType
{
Item,
Fee,
Discount
}
现在,您可以在order类中拥有:
public IList<OrderItem> Fees
{
get
{
return _items.Find(i=>i.ItemType==ItemType.Fee);
}
}
公共IList费用
{
得到
{
返回_items.Find(i=>i.ItemType==ItemType.Fee);
}
}
现在您仍然可以保留单个列表并避免额外的接口。您甚至可以有一个类似IList GetItems(ItemType)的方法
另一个想法是,您当前的设计不允许有%的折扣。今天你可以打九折。这可能不是一个要求,但是一个避免应用程序必须计算的选项是将项目与折扣分开
如果我订购10件商品,折扣甚至可能变得更为严格,可以打5%的折扣 我将向您介绍罗伯·康纳利(Rob Connery)不久前在我听的ALT.net播客上的一句话(我不是ALT.net的拥护者,但理由似乎很合理): 什么对“业务用户”有意义(如果你身边有这样的人的话) 作为一名程序员,你需要考虑项目、费用、折扣等因素,因为它们具有相似的属性和行为 但是,就模型而言,它们可能是两个完全不同的概念。有人稍后会来,说“但这没有意义,它们是独立的东西,我需要单独报告它们,我需要将这一特定规则应用于这种情况下的折扣” DRY并不意味着限制您的模型,当通过继承或类似的方式分解行为时,您应该注意这一点 在该案例中使用的具体示例是购物车。程序员的自然想法是在非限制状态下使用订单。这是有道理的,因为它们看起来完全一样。 但事实并非如此。这对客户来说毫无意义,因为它们是两个独立的概念,只会让设计变得不那么清晰 这是一个实践、品味和观点的问题,所以不要盲目地听从网站上的建议:) 针对您的具体问题,我使用的系统使用商品、费用、商品折扣(商品的属性)和订单的全局折扣(虽然它不是订单,但它是POS收据,但在这种情况下并不重要) 我猜原因是,在这些概念背后,物品是库存物品的具体实例,它们影响库存数量,它们是可枚举和可量化的 费用并不昂贵。它们不共享大多数属性
在您的情况下,这可能无关紧要,因为您的领域似乎比这要有限得多,但您可能希望记住这些问题。实际上,我会详细查看您的设计,并尝试找出行为的所在;然后将这些行为中的任何共性提取到一个独特的接口中,并确保其适用于您的设计 也就是说;费用可能具有与其关联的验证行为。假设您向任何包含20项或更多项的订单添加费用(这只是一个随机示例,请与我一起运行)。现在,当您添加第20项时,您可能希望将该费用添加到订单中,但出现了一个问题;当您从订单中删除某个项目时,是否每次都要检查以确定是否需要从订单中删除该费用?我对此表示怀疑;这里的含义是,有一种与费用/折扣相关的行为,本质上使其成为一个完全不同的类别 我会这样看;将费用和折扣归类为“特殊”内容,然后创建一个“ISpecial”界面,费用和折扣都从该界面继承。将任何通用功能提取到ISPSpecial接口(例如,“验证”)。然后让您的订单实现ISPSpecial(或其他)接口 通过这种方式,您可以定义特定的Fee.Validate()行为和折扣.Validate行为,并且由于多态性的魔力(对于m_specialCollection.Validate的每一个)可以使这些行为正常运行。通过这种方式,您也可以轻松地扩展
enum ItemType
{
Item,
Fee,
Discount
}
public IList<OrderItem> Fees
{
get
{
return _items.Find(i=>i.ItemType==ItemType.Fee);
}
}
public class ProductItem : OrderItem
{
public Item Item { get; set; }
public string Description { get { return Item.Description; } }
public int Quantity { get; set; }
public decimal Amount { get { return Item.Price * Quantity; } }
}
public void AddItem(OrderItem item)
{
_Items.Add(item); // note that backing field is a List<OrderItem>
}
Order o = new Order();
o.AddItem(new ProductOrderItem { Item = GetItem(1), Quantity = 2 });
o.AddItem(new FeeItem { Description = "Special Fee", Amount = 100 });
o.AddItem(new DiscountItem { DiscountAmount = .05 });
public decimal TotalFees
{
get
{
return (from OrderItem item in Items
where item is FeeItem
select item.Amount).Sum();
}
}
public void SetDiscountAmount(decimal discountAmount)
{
DiscountOrderItem item = _Items
.Where(x => x is DiscountOrderItem)
.SingleOrDefault();
if (item == null)
{
item = new DiscountOrderItem();
_Items.Add(item);
}
item.DiscountAmount = discountAmount;
}