2011-12-17 2 views
1

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

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

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

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

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

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

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

ответ

1

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

Общий базовый класс содержит значение setter и значение getter, которые используют отражение для установки и получения свойств внутри класса. Если запрашиваемое свойство отсутствует и вызывающий указывает, что это нормально, сеттер добавляет значение в пользовательскую область (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

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

dynamic productX = GetProduct(); 
productX.Price = "95,3€"; 
Смежные вопросы