Какой шаблон проектирования использовать в этом механизме синтаксического анализа? - PullRequest
1 голос
/ 17 декабря 2011

Я пытаюсь заполнить товары значениями, проанализированными на веб-сайте.Процесс идет нормально.То, что я хочу, - это простой способ (с уменьшенным соединением) легко заполнять значения в продуктах.На данный момент способ добавления значения выглядит так: 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);
}

, и есть несколько классов, производных от атрибута AA:

  • StringAtribute,
  • StringListAtribute,
  • KeyValueStringListAtribute,
  • BoolAtribute
  • NumericAtribute

Я создал этот дизайн, чтобы другие классыНе нужно знать, какой атрибут ведьмы какого типа и как им присваивать значения.Если, например, я хочу присвоить значение атрибуту Price, я бы сказал:

productX.Attributes[Price].SetValueFromString("95,3€");

Это действительно помогло, поскольку существует более 40 атрибутов.Было бы больно разбирать значения для каждого вручную.

Моя проблема в том, что я не хочу уменьшать еще больше связи.Любые идеи о том, как сделать, чтобы другие классы не знали об атрибутах AA или типах продуктов?Что-то между декоратором и шаблоном стратегии должно сработать, но я не могу найти путь к нему.

Проблема, которая заставляет меня задавать этот вопрос: - Как я могу добавить значения к ListStringAttribute?

Но это поднимает проблему, и я знаю, что мне нужен рефакторинг.

Ответы [ 2 ]

1 голос
/ 18 декабря 2011

То, как мы справляемся с этим, заключается в том, что все наши бизнес-классы наследуются от общего базового класса.

Общий базовый класс содержит установщик значения и получатель значения, которые используют отражение для установки и получения свойств в классе.Если запрошенное свойство отсутствует, и вызывающая сторона указывает, что это можно сделать, установщик добавляет значение в коллекцию пользовательских полей (UDF), которая аналогична вашим атрибутам.

Этот подходустраняет необходимость вызывающей стороны знать что-либо о том, как на самом деле хранятся значения (т. е. является ли оно обычным свойством в классе или в коллекции UDF) или даже о том, какой это тип данных.

Например, ваш код вызывающей стороны:

productX.Attributes[Price].SetValueFromString("95,3€");

в нашей системе будет:

productX.SetFieldValue("Price", "95,3€");

Мы широко используем это для взаимодействия с базой данных, связывания данных формы и т. Д.

Вот примеросновной метод установки:

    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
        }
    }

И один из методов получения, где мы получаем значение в виде строки:

    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), чтобы вы могли видеть, как они используются, но их довольно просто реализовать.

0 голосов
/ 24 декабря 2011

А как насчет наследования от DynamicObject? Расширение TrySetMember позволит вам сделать это:

dynamic productX = GetProduct();
productX.Price = "95,3€";
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...