4
votes

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 and saved.

Example.

If the user selects a type of paint that allows custom color matches, then I must allow them to enter in a formula number that they received through a color match process. So I have an Order Detail item for a Product that is a type of Paint, and that sku has the attribute of "AllowsCustomColorMatch", but I need to store the Formula Number somewhere also.

I'm not sure how to handle this elegantly throughout my code. Should I be creating subclasses or products? Right now I'm saving the data the user enters in an OrderDetails object that has a reference to the Product it is associated with.

4

4 Answers

5
votes

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.

2
votes

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.

0
votes

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.

0
votes

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).