在此解析机制中使用哪个设计模式

本文关键字:设计模式 机制 | 更新日期: 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€";