Я думаю, что суть проблемы, с которой вы здесь сталкиваетесь, заключается в том, что вы реализовали OrderItem
как подкласс Item
, и теперь вы обнаруживаете, что это действительно не всегда уместно.
Учитывая то, что вы описываете, вот как я бы попытался реализовать это:
Создайте класс Order
, который реализует общедоступные свойства для каждого однозначного элемента данных, который вы хотите отобразить для привязки данных: номер заказа, дата, клиент, общие сборы, общие скидки и т. Д. Похоже, что вы необходимо отобразить конкретные сборы / скидки в виде отдельных значений; если так, реализуйте общедоступные свойства для них.
Создайте абстрактный класс OrderItem
, который реализует общедоступные свойства для каждого элемента данных, с которым вы хотите связать сетку, и для каждого элемента данных, с которым вы хотите отсортировать элементы. (Вы также можете сделать это интерфейсом IOrderItem
; это действительно зависит от того, будут ли методы, общие для всех позиций заказа.)
Создание подклассов OrderItem
(или классов, реализующих IOrderItem
) для определенных типов позиций, которые могут появляться в заказе: ProductOrderItem
, FeeOrderItem
, DiscountOrderItem
и т. Д.
В вашей реализации ProductItem
реализуйте свойство типа Item
- это будет выглядеть примерно так:
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; } }
}
Реализовать свойство типа IEnumerable<OrderItem>
в Order
для хранения всех позиций. Реализуйте метод AddItem
для добавления OrderItems
, например ::
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();
}
}
Вы можете вернуться позже и при необходимости оптимизировать эти свойства (например, сохранить вычисления, как только вы сделали это один раз).
Обратите внимание, что вы также можете ограничить AddItem
добавлением ProductItem
s и использовать другие методы в Order
для добавления других типов элементов. Например, если заказ может иметь только одну сумму скидки:
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;
}
Вы бы использовали этот подход, если вы хотите отобразить сумму скидки в соответствующем месте в таблице позиций заказа, но также хотите, чтобы сумма скидки для заказа составляла одно значение. (Можно утверждать, что вы можете захотеть сделать DiscountAmount
свойством Order
, создать DiscountOrderItem
в его установщике и получить DiscountOrderItem
его Amount
от Order.DiscountAmount
. Я думаю, что оба подхода имеют свои плюсы и минусы.)