Создать производный класс в базовом классе на основе параметра

Мой вопрос более или менее идентичен Нужен шаблон проектирования для удаления перечислений и переключения оператора при создании объекта Однако я не вижу, чтобы абстрактный фабричный образец хорошо здесь подходил.

В настоящее время я планирую рефакторинг / повторную реализацию некоторых существующих библиотек DAL / ORM. Где-то в существующем коде есть код, который выглядит так:

class Base
{
static Base * create(struct Databasevalues dbValues)
{
switch(dbValues.ObjectType)
{
case typeA:
return new DerivedA(dbValues);
break;
case typeB:
return new DerivedB(dbValues);
break;
}
}
}

class DerivedA : public Base
{
// ...
}

class DerivedB : public Base
{
// ...
}

Таким образом, библиотека, отвечающая за связь с базой данных, заполняет структуру всей информацией об объекте базы данных, а затем вызывается вышеуказанный метод create (), чтобы фактически создать соответствующий объект в ORM.
Но мне не нравится идея о том, что базовый класс знает все его производные классы, и мне не нравится оператор switch. Я также хотел бы избежать создания другого класса только с целью создания этих объектов. Что вы думаете о нынешнем подходе? Как бы вы реализовали эту функциональность?

4

Решение

Независимо от того, что вы делаете, вам понадобится либо switch-case, либо какая-либо другая конструкция, которая будет просто скрывать подобную логику.

Однако вы можете и должны удалить метод create из вашей базы — вы совершенно правы, он не должен знать о его производных. Эта логика принадлежит другому объекту, например, фабрике или контроллеру.

1

Другие решения

Это обсуждалось здесь миллионы раз. Если вы не хотите создавать отдельный класс фабрики, вы можете сделать это.

class Base
{

public:
template <class T>
static void Register  (TObjectType type)
{
_creators[type] = &creator<T>;
}

static Base* Create (TObjectType type)
{
std::map <TObjectType, Creator>::iterator C = _creators.find (type);
if (C != _creators.end())
return C->second ();

return 0;
}

private:
template <class T>
static Base* creator ()
{
return new T;
}

private:
typedef Base* (::*Creator) ();
static std::map <TObjectType, Creator> _creators;
};

int main ()
{
Base::Register <Derived1> (typeA);
Base::Register <Derived2> (typeB);

Base* a = Base::Create (typeA);
Base* b = Base::Create (typeB);
}
6

Допустим, вы замените переключатель с отображением, как map<ObjectType, function<Base* (DatabaseValues&)>>,

Теперь фабрике (которая может или не может жить в базовом классе) не нужно знать обо всех подклассах.

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

3

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

Рассмотрим вместо такого перечисления:

enum Types {
typeA,
typeB
};

это конструкция, которая не требует переключения (еще одна не OO конструкция на мой взгляд) и карты:

types.h

class Base;
class BaseFactory {
public:
virtual Base* create() = 0;
};
class Types {
public:
// possible values
static Types typeA;
static Types typeB;
// just for comparison - if you do not need - do not write...
friend bool operator == (const Types & l, const Types & r)
{ return l.unique_id == r.unique_id; }
// and make any other properties in this enum equivalent - don't add them somewhere else
Base* create() { return baseFactory->create(); }

private:
Types(BaseFactory* baseFactory, unsigned unique_id);
BaseFactory* baseFactory;
unsigned unique_id; // don't ever write public getter for this member variable!!!
};

Types.cpp

#include "Types.h"#include "Base.h"#include "TypeA.h"#include "TypeB.h"
namespace {
TypeAFactory typeAFactory;
TypeBFactory typeAFactory;
unsigned unique_id = 0;
}
Types Types::typeA(&typeAFactory, unique_id++);
Types Types::typeA(&typeBFactory, unique_id++);

Итак, ваш пример (если вам действительно нужна эта функция):

class Base
{
static Base * create(struct Databasevalues dbValues)
{
return dbValues.ObjectType.create();
}
};

Недостающие части должны быть легко осуществимы.

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector