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

时间:2011-12-17 18:22:46

标签: c# design-patterns

我正在尝试使用从网站解析的值来填充产品。这个过程很顺利。我想要的是一种简单的方法(减少耦合),以便轻松填充产品中的值。 目前,添加值的方式如下: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

但这会引发问题并且知道我觉得有必要进行重构。

2 个答案:

答案 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€";