tags:

views:

133

answers:

9
+2  Q: 

OO Design question

I have a two types of products - Discounted (10% Disc) and NonDiscounted (0%) Each of these can be either LocalProduct / ExportableProduct with export one attracting a 15% sales tax.

What is the best way to model this scenario. Me being absolute newbie to S/W design, I have very limited ideas 1. To have 4 different Product sub types 2. Use Strategy pattern and have 4 different strategies.

Can some one please suggest how can I model this effectively using the above options or other ones.

+1  A: 

There is a similar post which might help:

http://stackoverflow.com/questions/2253475/discount-strategy-in-shopping-cart-and-orders/

Péter Török
+1  A: 

To keeps things simple, ask yourself if discount really need to be a subtype, or if it could be a property of the product, where "NonDiscounted" have a discount of zero percent.

crunchdog
A: 

I would suggest that perhaps Discounted/NonDiscounted should not be types of products at all. Instead have two subtypes, and a 'discount' property/field in the parent Product. Each product can then effectively have any discount. This also allows for discount that aren't fixed at 10%.

Tom Castle
+1  A: 

I would do this:

Have an class called "Product" that has the basic properties of a product like name, description, type, etc.

The base "Product" class can have a property called "DiscountRate". It can be 0 for non discounted and whatever value for discounted. This will help simplify calculation since the same formula will always be applied, just in one case the discount is 0.

Then you can have two classes "ExportableProduct" and "LocalProduct", they both inherit from the "Product" class.

Emad
A: 

I'd avoid inheritance (ie sub typing) just for this.

Instead I'd define enumerations for Discounted / NonDiscounted and Local / ExportableProduct. Each product class would then simply have a property for each of these indicating its type.

Then in a separate class, eg: PricingCalculator, define a Calculate method (possibly static) that accepts an instance of a product. This method simply examines the enumeration properties and applies the required percentage values in the calculation.

This completely separates the calculation of pricing from the products themselves and allows you to keep sometimes complex pricing calculations in one location. As your pricing schemes change over time, this approach is easily maintainable and testable.

Ash
A: 

I would avoid everything and just have two properties: discount and local

Since there is only one thing that changes (price), you can calculate it on the fly (discount => price * .9, export => price * .85 - or even both => export & discount => price * .9 * .85)

Adam Kiss
A: 

Inheritance is especially useful when more than thing varies according to the type.

For example if the discount, and the tax, and the shipping method all varied depending on the type of item, then it's definitely time to consider inheritance and subclassing (where you'd say "this subtype of item has this tax and this discount and this shipping").

On the other hand when only one thing varies according to the type, then it's less obvious whether it's worth having several types (i.e. a base type with subclasses), or instead whether that variance can be modeled more simply as a single type, whose instances have a property value (e.g. named "discount_percentage").

ChrisW
A: 

Classes distinguish sets of behavior. So let's take a look at your divisions in those terms:

  • While an argument could be made that discounted/non-discounted is a variation in behavior, it's trivial to reduce this to a single behavior: All products have a discount, but the amount of the discount happens to be 0% on non-discounted products. This is just an attribute of your products (discount_amount), not a separate class.

  • Local/exportable may or may not have distinct behaviors. If the only difference is whether the product is allowed to be shipped internationally or not, then a simple boolean flag should handle this distinction more than adequately. If, on the other hand, exportable products require behaviors not supported by local products (e.g., recording of customs requirements and procedures), then it would be appropriate to either make ExportableProduct a subclass of LocalProduct (if exportable product behaviors are a superset of local product behaviors) or make an abstract Product class with LocalProduct and ExportableProduct subclasses (if local products also have behaviors which are not supported by exportable products).

Dave Sherohman
A: 

When this is all the behaviour you are going to need, just having two booleans in your product and switching on them is the best solution. YAGNI.

But I'm afraid it's just a small part of a larger problem. And then you have to ask yourself: what makes a product a product (single responsibility). Taxability and discountability are probably two different concerns, so your product ends up with two strategies.

Stephan Eggermont