views:

36

answers:

2

I need some advice on how to model this simple categorization (?) example:
I have a product. A product can be of different types, such as ProductType 1, ProductType 2, and ProductType 3. All products have a part number and a name. Where they differ, is the way their prices are calculated.

  • Products in type 1's price are dependent on how many there are of the product. So if I have 5 products, the price is $x. If I have 20 products, the price is $y, and so on.
  • Products in type 2’s price are dependent on each products weight. If the weight is 5 kg, the price is $x, and so on.
  • Products in type 3’s have a simple price, like $x for each product.

The way I see it, each “price structure” needs to have a dedicated table/class. A product will then have a reference to its price structure, dependant on the type of the product. Would you just create a “product type” table and have an attribute called Type on the Product class, or would you use generalization, so Product 1/2/3 are a subtype of Product? There will be like 5 different price structures, and the way the price is calculated differs from each type. So the logic calculating the total price for an order is dependent on each product type.

Can you give me some advice on how to model this the best way? If I choose the approach where there’s a Type attribute on the Product class, I imagine that I will get lots of if-else statements in my code. Where if I choose to subclass them, each class can be responsible for calculating the correct price, or whatever it is asked to do.

+1  A: 

My suggestion is that in your relational data model, you will have the type column to distinguish the record type. In the code, you should definitely use sub-classing. The domain model should be independent of the underlying data model as much as possible and your description well support the need of sharing attributes (using ABC - abstract base class for Product), subtype to P1, P2, P3 (give it a meaningful domain name) and polymorphism to vary the price calculation.

Your order will hold a list of base product reference and to get the total, you will ask each product for the price and accumulate them using iterator.

Fadrian Sudaman
Thank you for you comment. Why not model the subclassing like described here? http://www.tomjewett.com/dbdesign/dbdesign.php?page=subclass.php
Tommy Jakobsen
Modeling subclass in the db is not suitable for your scenario. When your subclass have distinctive set of attributes, you will then consider that like in the example link you sent. In your case, the only variation is the type and calculation, which is derived and not stored/cached against a field in the db. If you model it in the db, you will end up having the Product table with 3 other Product' tables and all it has is a FK with 1:0 relationship
Fadrian Sudaman
Good point. Thank you very much. I'm still open to other comments and suggestions.
Tommy Jakobsen
A: 

This sounds to me like a perfect example of when to use the Strategy pattern. If you use class inheritance to define how a product is priced, you'll have to re-compile your entire system if someone later decides WidgetXYZ should now be priced by weight, instead of having a simple price.

I would define each product as having a "PricingStrategy" - in your case this would be either "volumeDiscount", "byWeight", or "simple". You could then use a Factory to provide the correct PriceCalculator object depending on the product's strategy, and that priceCalculator would calculate the product's price accordingly.

mikemanne
I will have to look into this approach. Thank you for your suggestion! I'll probaly return here in a few days when I know more about it.
Tommy Jakobsen
I've successfully implemented the strategy and factory patterns to solve my problem and it seems like a good solution. Thank you!
Tommy Jakobsen