I am building an application that is very similar to a shopping cart. The user selects a product from a list, and then based on that product, a few properties need to be set an
Depending on how you have you current objects setup; I would create 2 Paint classes. The first Paint class takes all the common properties/fields found in paint. I would then create a second class, we'll call it PaintSpecialize. PaintSpecialize will inherit from Paint (giving this class all of Paint's properties and methods). In PaintSpecialize you can then add the Formula property to the class. After which, it's just a matter of casting the objects. C# ex:
public class Paint {
private decimal _price;
private bool _allowFormula;
public Paint() { ... }
public Paint(int price) {
_price = price;
}
public ChangePrice(decimal p) {
_price = p;
}
}
And so on.
PaintSpecialize would look something like this:
public class PaintSpecialize : Paint {
string _formula;
[...]
public PaintSpecialize(int price, string formula) : base(price) {
_formula=formula;
}
After in code it's possible to:
PaintSpecialize ps = new PaintSpecialize(15.00, "FormulaXXYY");
ps.ChangePrice(12.00);
List<Paint> plist = new List<Paint>();
plist.Add((Paint)ps);
foreach(Paint p in plist) {
if(p.AllowFormula) {
PaintSpecialize tmp = (PaintSpecialize)p;
MessageBox.Show(tmp._formula);
}
The above code gives a simple (and not very complete) look at what you can do with paint. The list can now contain both Paint and PaintSpecialize as long as the latter is casted properly. You can manipulate the PaintSpecialize in the list at anytime simple by casting it form a simple Paint to a PaintSpecialize.
So if the customer wants regular paint, create a Paint object, if he wants a custom paint, create a PaintSpecialize. If the customer wants a regular and custom paint, create one of each. Refer to both of them as Paint until you need to use something from the PaintSpecialize class.
Note that the AllowsCustomColorMatch attribute should be set in the base class otherwise you'll probably have to work a little harder to figure out if the class is of the PaintSpecialize type.
Since you're looking into an elegant solution, you may want to take a look at the Adaptive Object-Model Architectural style. You can search here, or here. Basically your problem can be solved by simply using the TypeSquare pattern, with maybe the Interpreter pattern for the business rules (if it ever gets that complex).
I would avoid making a class for each product. Each of your products are instances of the same Product class.
With such variable properties, a dictionary approach (basically a map of key-value pairs, type specific or not, is a great way to retain flexibility in the design. You aren't talking about amazon.com sized product inventory, so I think it is a good enough design for the perf you need.
You can have a Product class with a collection of product properties
public class Product
{
private Dictionary<string, string> properties;
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
public string Name
{
get;
set;
}
/// <summary>
/// Gets or sets the price.
/// </summary>
/// <value>The price.</value>
public double Price
{
get;
set;
}
public Dictionary<string, string> Properties
{
get;
}
public Product()
{
properties = new Dictionary<string, string>();
}
}
In the datasource you can have a table that defines the properties to each type of product. Then when you render the page you know what properties to show and the name to give in the dictionary.