我正在尝试使用从网站解析的值来填充产品。这个过程很顺利。我想要的是一种简单的方法(减少耦合),以便轻松填充产品中的值。
目前,添加值的方式如下:productX.Attributes[Price].SetValueFromString("95,3€");
。请参阅下面的设计并帮助我改进它。
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);
}
并且有几个派生自AAtribute的类:
StringAtribute
,StringListAtribute
,KeyValueStringListAtribute
,BoolAtribute
NumericAtribute
我做了这个设计,所以其他类不需要知道巫婆属性是什么类型以及如何给它们赋值。 例如,如果我想给Price属性赋值,我会说:
productX.Attributes[Price].SetValueFromString("95,3€");
这确实有帮助,因为有超过40个属性。用手解析每一个的价值会很痛苦。
我的问题是我不想减少更多的耦合。关于如何让其他课程不知道AAtributes或产品类型的任何想法?装饰者和战略模式之间应该做的事情,但我找不到办法。
引导我提出这个问题的问题是:
- 如何将值添加到ListStringAttribute
?
但这会引发问题并且知道我觉得有必要进行重构。
答案 0 :(得分:1)
我们处理这个问题的方法是所有业务类都从公共基类继承。
公共基类包含值setter和值getter,它使用反射来设置和获取类中的属性。如果请求的属性不存在且调用者指示可以这样做,则setter会将值添加到用户定义的字段(UDF)集合中,该集合与您的属性类似。
这种方法消除了调用者需要知道值实际存储的任何信息(即它是类或UDF集合中的常规属性),甚至是什么数据类型。
例如,您的来电者代码:
productX.Attributes[Price].SetValueFromString("95,3€");
我们系统中的将是:
productX.SetFieldValue("Price", "95,3€");
我们广泛使用它来进行数据库交互,表单数据绑定等。
以下是核心setter方法的示例:
public static void SetFieldValue(object oRecord, string sName, object oValue)
{
PropertyInfo theProperty = null;
FieldInfo theField = null;
System.Type oType = null;
try
{
oType = oRecord.GetType();
// See if the column is a property in the record
theProperty = oType.GetProperty(sName, BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public, null, null, new Type[0], null);
if (theProperty == null)
{
theField = oType.GetField(sName, BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public);
if (theField != null)
{
theField.SetValue(oRecord, Global.ValueFromDB(oValue, theField.FieldType.Name));
}
else
{
object[] aAttributes = null;
// See if the class type is decorated with the NoUDFs attribute. If so, do not add the attribute.
aAttributes = oType.GetCustomAttributes(typeof(NoUDFsAttribute), true);
if (aAttributes.Length == 0)
{
// Otherwise, anything that is not found as a property or a field will be stored as a UDF
oRecord.SetUDFValue(sName, oValue);
}
}
}
else
{
if (theProperty.CanWrite)
{
theProperty.SetValue(oRecord, Global.ValueFromDB(oValue, theProperty.PropertyType.Name), null);
}
}
}
catch (Exception theException)
{
// Handle the exception
}
}
其中一个getter方法,我们将值作为字符串获取:
public static string GetFieldValueForSQL(object oRecord, string sName)
{
PropertyInfo theProperty = null;
FieldInfo theField = null;
System.Type oType = null;
try
{
oType = oRecord.GetType();
// See if the column is a property in the record
theProperty = oType.GetProperty(sName, BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public, null, null, new Type[0], null);
if (theProperty == null)
{
theField = oType.GetField(sName, BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public);
if (theField != null)
{
return Global.ValueForSQL(theField.GetValue(oRecord), theField.FieldType.Name);
}
else
{
UDF oUDF = null;
object[] aAttributes = null;
// See if the class type is decorated with the NoUDFs attribute. If so, do not get the value.
aAttributes = oType.GetCustomAttributes(typeof(NoUDFsAttribute), true);
if (aAttributes.Length == 0)
{
oUDF = oRecord.GetUDF(sName);
}
if (oUDF != null)
{
return Global.ValueForSQL(oUDF.Value);
}
else
{
return "Null";
}
}
}
else
{
return Global.ValueForSQL(theProperty.GetValue(oRecord, null), theProperty.PropertyType.Name);
}
}
catch (Exception theException)
{
// Handle the exception
return null;
}
}
我已经离开了一些内部方法调用,我们使用它来将值强制转换为适当的格式(ValueFromDB,ValueForSQL),以便您可以看到它们的使用方式,但它们非常简单易用。
答案 1 :(得分:0)
从DynamicObject继承怎么样?扩展TrySetMember将允许您执行此操作:
dynamic productX = GetProduct();
productX.Price = "95,3€";