For example, I assert that you do not need any of those
interfaces. If needed later, make them later.
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.
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
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
abstract class for your
"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
interfaces and make an
abstract class if you must sub-class
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.