2009-04-28 2 views
6

나는 다른 개발자가 조언을 구하거나 "당신 생각은 무엇입니까?"라고 생각합니다. this "하시기 바랍니다. 시간을내어 읽고 생각을 알려주세요.주문 클래스에 수수료/할인 목록을 통합하거나 아이템 라인으로 만들 수 있습니까?

설명보다 쉽게 ​​표시 할 수 있지만 앱은 본질적으로 3 가지 주요 항목 인 항목, 주문 항목 및 주문이있는 판매 시점 앱과 같습니다.

항목 클래스는 데이터 저장소의 데이터입니다.

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 = new Order(); 
// Fee 
order.Add(new OrderItem(new Item("Admin Fee", 20), 1)); 

// Discount 
order.Add(new OrderItem(new Item("Today's Special", -5), 1)); 

는 의미와 순서가있는 항목을 통해 반복에서 상속 기본 클래스를 만든다 : 당신이 주문에 수수료 또는 할인을 추가 할 때와 같이

public class OrderItem 
    : Item, IBillableItem, IComparable<OrderItem>, IEquatable<OrderItem> 
{ 
    // IBillableItem members 
    public Boolean IsTaxed { get; set; } 
    public decimal ExtendedCost { get { return Cost * Quantity; } } 

    public Int32 Quantity { get; set; } 

    public OrderItem (Item i, Int32 quantity) 
     : base(i.ID, i.Description, i.Cost) 
    { 
     Quantity = quantity; 

     IsTaxed = false; 
    } 
    // Extraneous Detail Omitted 
} 

현재는 간단합니다 리스트를 만들고, 적절한 세금을 계산하며, 2가있는 다른 Order-type 문서가 무엇이든지 다시 임 플리 멘팅하지 않고이 모든 것을 계산하는 기본 클래스로부터 상속받을 수있게합니다. 주문 유형 문서에 할인이없는 경우에는 $ value OrderItem을 추가하지 않는 것만 큼 쉽습니다.

유일한 문제는이 데이터를 표시하는 것입니다. 이 양식에는 판매 품목 (예 : 수수료/할인 제외)이 표시되어야하는 표가 있습니다. 마찬가지로 특정 수수료 및 특정 할인에 대한 텍스트 상자가 있습니다. 이 클래스의 필드에 해당 요소를 데이터 바인딩하여 사용자 (나)가 더 쉽게 사용할 수있게하고 싶습니다. IHasFees, IHasDiscounts을하고 주문을 구현할 수있다;

아이디어 발상

2 인터페이스를 가지고 둘 다 List의 단일 구성원을 갖습니다. 그렇게하면 판매 품목, 수수료 및 할인 만 이용할 수 있습니다 (필요한 경우 통제에 묶을 수 있음). 내가 좋아하지 않는 무엇

: 가 - 지금은 클래스 (AddItem을/AddFee/AddDiscount/제거 ...) 가 방법을 제거/3 가지 추가 기능을 가지고있다 - 나는 복제하고있어 (triplicating?) 기능은 모두 동일한 유형의 항목 목록에 불과하므로 각 목록마다 다른 의미가 있습니다.

올바른 경로에 있습니까? 나는 이것이 대부분의 사람들에게 (이 유형의 소프트웨어가 매우 일반적이라고 생각할 때) 해결 된 문제라고 생각한다.

+7

IHasFees 및 IHasDiscounts 소리 hauntingly LOLCats 좋아해. –

답변

3

나는 (내가 ALT.net 옹호 아니지만, 추론 소리 듯) 내가 얼마 전에에 귀를 기울 ALT.net 팟 캐스트에 롭 코너리에 의해 발언에 당신을 가리킬 수 있습니다 :

무엇 "비즈니스 사용자"(주위 사람이있는 경우)에게 의미가 있습니다.

프로그래머는 Item, Fee, Discount 등을 고려해야합니다. 속성, 동작이 비슷하기 때문입니다.

그러나 모델 측면에서 볼 때 두 개의 완전히 다른 개념 일 수 있습니다. 그리고 누군가 나중에 나올 것입니다. "하지만 이것은 별 의미가 없습니다. 그들은 별개의 것입니다. 따로 따로보고해야하며이 규칙을 할인에 적용해야합니다."

DRY는 모델을 제한하는 것이 아니라 상속 등을 통해 동작을 분해 할 때주의해야합니다.

이 경우 사용 된 구체적인 예는 장바구니의 특정 예입니다. 프로그래머의 당연한 생각은 커밋되지 않은 상태에서 주문을 사용하는 것이 었습니다. 그리고 그들은 똑같이 보이기 때문에 의미가 있습니다. 그렇지 않은 경우를 제외하고 그것들은 두 개의 분리 된 개념이기 때문에 클라이언트에게는 이해가되지 않으며, 단지 디자인을 덜 명확하게 만듭니다.

그것은 너무 맹목적으로 웹 사이트에 게시 조언을 따르지 않는,하지만 관행, 맛과 의견의 문제입니다 :)

그리고 특정 문제에 대한

, 내가 사용하는 항목, 수수료와 함께 작동 시스템, 라인 아이템 할인 (아이템의 속성)과 주문에 대한 글로벌 할인 (주문이 아니지만 POS 영수증이지만 그 경우에는 중요하지 않습니다).

그 이유는 항목이 조사 대상 조각의 특정 인스턴스이고, 재고 수량에 영향을 주며, 열거 가능하고 수량화 할 수 있기 때문입니다.

수수료가 없습니다. 그들은 대부분의 속성을 공유하지 않습니다.

귀하의 도메인이 그보다 훨씬 제한적이지만 귀하가 염두에 두어야 할 사항이 있으므로 귀하의 경우 중요하지 않을 수 있습니다.

+0

+1 : 할인 항목을 주문하는 항목으로 보는 데 어려움을 겪고 있습니다. 요금은 늘릴 수 있지만 ILineItem을 정의하여 모델링 할 수 있습니다. 설명 비용 & 수량은 주문의 광고 항목이 될 수 있습니다. 나는 그것들이 같은 유형 인 경우에도 Item & Discount와는 별도로 주문에 노출시킬 것입니다. – JoshBerke

+0

필자는 POS에서 일하는 시스템에서 실제로 요금을 책정하지 않았거나 영수증에 금액이 없어서는 안됩니다. 나는 계산 목적으로, 집계 목적 (총계/부분 계산)을위한 공통 인터페이스 구현을 행동 특성으로 말하면서 공유 할 수 있다는 것에 동의합니다. 나는 그것들을 같은 타입으로 만들지는 않을 것이다. (단지 장의 느낌). 다시 말하지만 전체 컨텍스트가 없거나 비즈니스 분석가에게 액세스 할 수없는 경우 "올바른 대답"을 제공하기가 어렵습니다. –

1

하나의 옵션 주문 클래스에서 지금

enum ItemType 
{ 
    Item, 
    Fee, 
    Discount 
} 

당신이 수를 OrderItem에하는 ItemType의 속성을 추가하는 것입니다이 있습니다

public IList<OrderItem> Fees 
{ 
    get 
    { 
     return _items.Find(i=>i.ItemType==ItemType.Fee); 
    } 
} 

지금 당신은 여전히 ​​하나의 목록을 유지하고 별도의 인터페이스를 방지 할 수 있습니다 . IList GetItems (ItemType 유형)와 같은 메소드를 사용할 수도 있습니다.

다른 생각으로는 현재 디자인이 % 할인을 허용하지 않는다는 것입니다. 오늘 당신은 10 % 할인됩니다. 이것은 요구 사항이 아닐 수도 있지만, 응용 프로그램이이를 계산하지 않도록하는 한 가지 옵션은 할인 항목을 분리하는 것입니다.

10 개 항목을 주문하면 5 % 할인 된 가격으로 할인 혜택을받을 수 있습니다.

+0

+1 나는이 아이디어를 좋아하고, 특히 할인이 규칙이되는 개념을 사용합니다 (영업 담당자 중 한 사람이 종종 이와 비슷한 것을합니다). –

+0

그래, 그 규칙보다 훨씬 복잡하지만 그 복잡성으로 당신이 할 수있는 멋진 것들이 많이옵니다. 특히 다시 컴파일하지 않고 새로운 규칙을 삽입 할 수 있다면 ... – JoshBerke

3

효과적으로, 나는 세부 사항에있는 당신의 디자인을보고 행동이 거짓말을 파악하는 것을 시도 할 것입니다; 그런 다음 해당 동작의 공통점을 고유 한 인터페이스로 추출하여 해당 디자인에 적용되는지 확인하십시오.

위트로; 수수료에는 관련 요금이 포함될 수 있습니다. 20 개 이상의 항목이있는 모든 광고 주문에 수수료를 추가한다고 가정 해 보겠습니다. 이제 20 번째 항목을 추가 할 때 해당 요금을 주문에 추가 할 수 있지만 문제가 있습니다. 주문에서 물건을 지울 때마다 매번 수표를 지워야하는지 확인하고 싶습니까? 나는 그것을 의심한다. 여기서 의미하는 바는 근본적으로 완전히 다른 종류의 사물을 만드는 요금/할인과 관련된 행동이 있다는 것입니다.

나는 이렇게 보았을 것이다. 수수료와 할인을 "특별"물건으로 분류 한 다음 수수료와 할인이 모두 상속되는 "ISpecial"인터페이스를 만듭니다. ISpecial 인터페이스에 공통 기능을 추출합니다 (예 : "유효성 검사"). 그런 다음 주문서에 ISpecial (또는 무엇이든) 인터페이스를 구현하게하십시오.

그런 식으로 특정 Fee.Validate() 동작과 Discount.Validate 동작을 정의하고 다형성 마법 (foreach가 이들의 유효성을 검증)을 통해 올바르게 작동하게 할 수 있습니다. 그런 식으로, 필요한 경우 (세금 등) 다른 인터페이스를 쉽게 확장 할 수 있습니다.

2

여기에 직면 한 문제의 핵심은 OrderItemItem의 하위 클래스로 구현했는데 이제는 이것이 항상 적절하지 않다는 것을 알게되었습니다. , 주문 번호 날짜 :

공공 데이터 바인딩에 노출 할 모든 단일 값 데이터 요소에 대한 속성을 구현하는 Order 클래스를 만듭니다

당신이 무엇을 설명 감안할 때, 여기에 내가이 구현 해보고 싶었어요 방법 , 고객, 총 요금, 총 할인 등. 특정 수수료/할인을 단일 값으로 표시해야 할 수도 있습니다. 그렇다면 공용 속성을 구현하십시오.

그리드에 바인딩하려는 모든 데이터 요소와 항목을 정렬 할 모든 데이터 요소에 대해 공용 속성을 구현하는 추상 클래스 OrderItem을 만듭니다. (당신은 또한이 IOrderItem 인터페이스를 만들 수 있습니다, 그것은 정말 모든 주문 항목에 일반적인 방법이있을거야 여부에 따라 달라집니다.)

는 특정 종류의 OrderItem의 서브 클래스 (또는 IOrderItem를 구현하는 클래스)를 작성 주문에 나타날 수있는 개별 항목 : ProductItem의 구현에 등

ProductOrderItem, FeeOrderItem, DiscountOrderItem는 입력 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 내에 구현하십시오. OrderItems를 추가하기위한 AddItem 방법을 구현, 예를 들면 :이 목록 예에서 값을 추출해야하는 단일 값 필드의

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 void AddItem(OrderItem item) 
{ 
    _Items.Add(item); // note that backing field is a List<OrderItem> 
} 

: (한 번 그것을 한 적이 한 번 예를 들면 계산을 저장)

public decimal TotalFees 
{ 
    get 
    { 
     return (from OrderItem item in Items 
       where item is FeeItem 
       select item.Amount).Sum(); 
    } 
} 

당신은 나중에 다시 필요한 경우 이러한 속성을 최적화 할 수 있습니다.

AddItemProductItem 초로 제한하고 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를 작성하고 DiscountOrderItemOrder.DiscountAmount로부터 Amount를 얻을 수 있습니다 할 수 있다는 논란의 여지가있다. 나는이 두 방법은 자신의 장점과 단점을 가지고 생각합니다.)

관련 문제