Premature Over-Engineering
For example, I assert that you do not need any of those interface
s. If needed later, make them later.
An interface
(the C# keyword kind) is for giving common behavior to unrelated classes and then handle objects polymorphically.
Think more carefully about what constitutes a more specific class. Think of what a shopping cart IS. Is a "coupon shopping cart" a more specific kind of cart, or is it simply an attribute in a cart?
Think more carefully about how things work together, in contrast to seeing everything as separate, distinct bits. A coupon is a logical part of calculating a price. GetPrice
is simply a necessary "grunt" method in a product class.
"groupsale" is a volume discount. This is the same concept as a coupon. Both are discounts. Said another way, they are simply adjustments to the price. Therefore they are an integral part of calculating cost. They are not classes.
Too much interface
Code to interfaces not implementation does not mean make everything a (C# keyword) interface
. Any class' set of public methods IS an interface.
Implementing interfaces instead of inheriting from an abstract class sets you up for lots of redundant implementation.
This is a grotesque (sorry) mis-application of the Interface segregation
principle. I cannot see how ISell
justifies itself as a distinct interface
. I do not see ISell
references being passed around. GetPrice()
simply looks like it naturally belongs to a ProductXXX
object; where its meaning is more clear inside of a functional class.
Ditto for the shopping cart.
Weight, Quantity Abstracted
Abstracted, I strongly suspect the multiple ProductSellBy...
classes coallece into one.
These are simply values. And these values are used in calculation in the same way, i.e. GetPrice() * Quantity()
The fact that quantity
represents countable things or weight can be captured by a separate property. You've already got an enum
for this, make a property of that type in the Product
class.
This abstraction does away with the motivation for the many interfaces and classes and your diagram will shrink by more than half I think.
DRY up redundant methods
Make an abstract
class for your Product
s.
ShoppingCart coupon
"By coupon" makes no sense as a shopping cart sub-class. A coupon is simply an adjustment to price calculation.
As above, get rid of those interface
s and make an abstract
class if you must sub-class ShoppingCart
.
And when you think about it, a coupon is not really a special case. A cost is coupon-discounted the same way for any item, I assume. So that discount can be built in to the price calculation. This is accomodated by the coupon's default value that would represent no discount.
PricingStrategy
interface and then implemented things likePerPoundStrategy
andXForXStrategy
. The hard part was actually to recalculate as each item was scanned, as the same UPC can be scanned "out of order" with another item(s) in between.