Вопрос по заводской схеме - PullRequest
3 голосов
/ 13 марта 2010

У меня есть фабричный класс для создания объектов базового класса B. Объект (D), который использует эту фабрику, получает список строк, представляющих фактические типы. Какова правильная реализация:

  1. фабрика получает Enum (и использует переключатель внутри функции Create), и D отвечает за преобразование строки в Enum.
  2. фабрика получает строку и проверяет совпадение с набором допустимых строк (используя ifs ')
  3. другая реализация, о которой я не думал.

Ответы [ 5 ]

1 голос
/ 13 марта 2010

Я бы разделил преобразование строк в enum в отдельный объект. Это может быть легко решено с помощью карты, кстати. Но обработка ошибок и т. Д. - все еще то, о чем ни D, ни фабрика не должны беспокоиться.

Затем либо D вызывает конвертер для получения его перечисления, либо он уже преобразован заранее, поэтому D нужно только передать перечисление на завод. (Кстати, на заводе лучше использовать карту вместо внутреннего переключателя).

Возникает вопрос: действительно ли вам нужны перечисления вообще (в местах, отличных от D и фабрики)? Если нет, то, возможно, перечисление можно было бы оставить вне рисунка, и вы могли бы использовать карту для преобразования непосредственно из строк в типы (т. Е. Поскольку C ++ не поддерживает динамическую загрузку классов) для функций объектов, которые создают необходимые конкретные экземпляры типов для вы). Грубый пример (у меня нет IDE для тестирования, так что потерпите меня, если в нем есть ошибки):

// Function type returning a pointer to B
typedef (B*)(*func)() StaticConstructor;

// Function creating instances of subclass E
B* createSubclassE() {
    return new E(...);
}

// Function creating instances of subclass F
B* createSubclassF() {
    return new F(...);
}

// Mapping from strings to constructor methods creating specific subclasses of B
map<string, StaticConstructor> factoryMap;
factoryMap["E"] = &createSubclassE;
factoryMap["F"] = &createSubclassF;

Конечно, созданные экземпляры также должны утилизироваться должным образом - в рабочем коде возвращаемые объекты могут быть, например, заключено в auto_ptr. Но я надеюсь, что этого короткого примера достаточно, чтобы показать вам основную идею. Вот учебник , если вы хотите больше ...

0 голосов
/ 13 марта 2010

Я лично использую расширенное перечисление, потому что мне всегда не хватало перечисления C ++: сообщения типа Type 3 - method -begin не очень информативны.

Для этого я использую простой шаблонный класс:

template <class Holder>
class Enum
{
public:
  typedef typename Holder::type enum_type;

  Enum(): mValue(Invalid()) {}
  Enum(enum_type i): mValue(Get(i)) {}
  explicit Enum(const std::string& s): mValue(Get(s)) {}

  bool isValid() const { return mValue != Invalid(); }
  enum_type getValue() const { return mValue->first; }

private:
  typedef typename Holder::mapping_type mapping_type;
  typedef typename mapping_type::const_iterator iterator;
  static const mapping_type& Mapping() { static mapping_type MMap = Holder::Initialize(); return MMap; }

  static iterator Invalid() { return Mapping().end(); }
  static iterator Get(enum_type i) { // search }
  static iterator Get(const std::string& s) { // search }

  iterator mValue;
};

Вы определяете Holder так:

struct Example
{
  typedef enum {
    Value1,
    Value2,
    Value3
  } type;

  typedef std::vector< std::pair< type, std::string > > mapping_type;

  static mapping_type Initialize() {
    return builder<mapping_type>()(Value1,"Value1")(Value2,"Value2")(Value3,"Value3");
  }
};

Вы можете определить макрос для него:

DEFINE_ENUM(Example, (Value1)(Value2)(Value3))

Но я позволю реализацию как упражнение (Boost.Preprocessor - твой друг).

Самое классное - использовать это!

int main(int argc, char* argv[])
{
  std::string s;
  std::cin >> s;
  Enum<Example> e(s);

  switch(e.getValue())
  {
  case Example::Value1:
  case Example::Value2:
    ++e;
  case Example::Value3:
    std::cout << e << std::endl;
  default:
  }
}
0 голосов
/ 13 марта 2010

Нормальный способ - иметь свой завод как синглтон. Затем каждый класс, основанный на классе B, регистрирует свою функцию создания и имя с фабрикой во время статической инициализации. Это часто делается с помощью макросов. Затем фабрика может создать быструю хеш-таблицу с таким именем для создания функций. И т.д ... вы получите дрейф.

0 голосов
/ 13 марта 2010

Мой проект на VC++/Qt содержал большое количество XML-файлов, содержащих строки, которые имели представление Enum в исходном коде.

Так что для каждого Enum у нас была оболочка с перегруженным оператором QString <> Enum:

enum DataColumnTypeEnum
{
    DataColumnTypeNotSet,
    ColumnBinary,
    ColumnBoolean,
    ColumnDate,
    ColumnDateTime,
    ColumnNumber,
    ColumnFloat,
    ColumnPrimary,
    ColumnString,
    ColumnText,
};

class DataColumnType
{
public:
    DataColumnType();
    DataColumnType(DataColumnTypeEnum);
    DataColumnType(const QString&);

    DataColumnType& operator = (DataColumnTypeEnum);
    DataColumnType& operator = (const QString&);

    operator DataColumnTypeEnum() const;
    operator QString() const;
private:
    DataColumnTypeEnum type;
};

DataColumnType& DataColumnType::operator = (const QString& str)
{
    str.toLower();
    if(str.isEmpty()) type = DataColumnTypeNotSet;
    else if(str == "binary") type = ColumnBinary;
    else if(str == "bool") type = ColumnBoolean;
    else if(str == "date") type = ColumnDate;
    else if(str == "datetime") type = ColumnDateTime;
    else if(str == "number") type = ColumnNumber;
    else if(str == "float") type = ColumnFloat;
    else if(str == "primary") type = ColumnPrimary;
    else if(str == "string") type = ColumnString;
    else if(str == "text") type = ColumnText;
    return *this;
}

но подход в последнем листинге очень уродлив.

Лучше создать статическую хеш-таблицу или словарь и посмотреть на нее.

0 голосов
/ 13 марта 2010

Вы можете поместить все подходящие строки в набор или список и проверить, содержат ли они ваши строки, вместо записи ifs / переключателей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...