在此解析机制中使用哪个设计模式
本文关键字:设计模式 机制 | 更新日期: 2023-09-27 18:18:14
我试图从网站解析值填充产品。这个过程很顺利。我想要的是一种简单的方法(减少耦合)来轻松地填充产品中的值。目前,添加值的方式是: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);
}
并且有几个类派生自aattribute:
-
StringAtribute
, -
StringListAtribute
, -
KeyValueStringListAtribute
, -
BoolAtribute
-
NumericAtribute
我这样设计是为了让其他类不需要知道属性是什么类型的,以及如何给它们赋值。例如,如果我想给Price属性赋值,我可以说:
productX.Attributes[Price].SetValueFromString("95,3€");
这真的很有帮助,因为有超过40个属性。手工解析每一个值是很痛苦的。
我的问题是我不想减少更多的耦合。关于如何使其他类不知道属性或产品类型有什么想法吗?应该是介于decorator和strategy pattern之间的东西,但是我找不到合适的方法。
导致我提出这个问题的问题是:-如何给ListStringAttribute
添加值?
但是这引起了问题,我知道我觉得有必要重构。
我们处理这个问题的方式是,我们所有的业务类都继承自一个公共基类。
公共基类包含一个值setter和一个值getter,它们使用反射来设置和获取类中的属性。如果请求的属性不存在,并且调用者指示可以这样做,则setter将值添加到用户定义字段(UDF)集合中,这与您的属性类似。
这种方法消除了调用者对值实际存储方式的任何了解(即它是类上的常规属性还是UDF集合中的常规属性),甚至不需要知道它是什么数据类型。
例如,您的呼叫者代码:
productX.Attributes[Price].SetValueFromString("95,3€");
在我们的系统中应该是:
productX.SetFieldValue("Price", "95,3€");
我们在数据库交互,表单数据绑定等方面广泛使用。
下面是一个core 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),以便您可以看到它们是如何使用的,但是它们实现起来非常简单。
如何从DynamicObject继承?扩展TrySetMember可以让你这样做:
dynamic productX = GetProduct();
productX.Price = "95,3€";