I am trying to fill products with values parsed from a website. The process goes fine. What I want is an easy way (with reduced coupling) to fill values in products easily.
At the moment, the way to add a value is like: productX.Attributes[Price].SetValueFromString("95,3€");. Please see the design below and help me improve it.
class Product
{
Dictionary<KeyValuePair<Type, AAtribute>> _attributes;
Product()
{
// add values to _attributes. for example
// Name with StrinAttribute
// Price with NumericAttribute
// Images with StringListAttribute
}
}
enum Type
{
Name,
Price,
Images
...
}
abtract class AAtribute
{
abstract void SetValueFromString(string value);
}
and there are several classes that derive from AAtribute:
StringAtribute,StringListAtribute,KeyValueStringListAtribute,BoolAtributeNumericAtribute
I’ve made this design so other classes don’t need to know witch attribute is of what type and how to give values to them.
If for example I want to give value to the Price attribute I would say:
productX.Attributes[Price].SetValueFromString("95,3€");
This has really helped since there are more than 40 attributes. It would be pain to parse value for each one by hand.
My problem is that I wan’t to reduce even more coupling. Any ideas on how to make other classes unaware of AAtributes or product types? Something between decorator and strategy pattern should do but I can’t find a way to it.
The problem that lead me make this question is:
– How can I add values to a ListStringAttribute?
But this rises the problem and know I feel there is a need for refactoring.
The way that we handle this is that all of our business classes inherit from a common base class.
The common base class contains a value setter and a value getter which use reflection to set and get properties within the class. If the requested property isn’t present and the caller indicates it is ok to do so, the setter adds the value to a user-defined field (UDF) collection, which is similar to your attributes.
This approach removes the caller’s need to know anything about how the values are actually stored (i.e. is it a regular property on the class or in the UDF collection) or even what data type it is.
For example, your caller code:
in our system would be:
We use this extensively for database interaction, form data binding, etc.
Here is an example of the core setter method:
And one of the getter methods where we get the value as a string:
I’ve left some of the internal method calls that we use to coerce the values into the appropriate format (ValueFromDB, ValueForSQL) in place so you can see how they are used, but they are pretty straightforward to implement.