Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我应该将费用/折扣列表合并到订单类中还是将其作为项目行_C#_Oop - Fatal编程技术网

C# 我应该将费用/折扣列表合并到订单类中还是将其作为项目行

C# 我应该将费用/折扣列表合并到订单类中还是将其作为项目行,c#,oop,C#,Oop,我没有其他开发人员可以征求意见或“你怎么想-我在想这个”,所以如果你有时间,请阅读并让我知道你的想法 显示比描述更容易,但该应用程序本质上类似于一个销售点应用程序,有三个主要部分:项目、订单项目和订单 item类是来自数据存储的数据 public class Item : IComparable<OrderItem>, IEquatable<OrderItem> { public Int32 ID { get; set; } public Str

我没有其他开发人员可以征求意见或“你怎么想-我在想这个”,所以如果你有时间,请阅读并让我知道你的想法

显示比描述更容易,但该应用程序本质上类似于一个销售点应用程序,有三个主要部分:项目、订单项目和订单

item类是来自数据存储的数据

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;
}