Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 07.07.2017, 20:05   #1
Aoizora
Заблокирован
 
Регистрация: 11.11.2016
Сообщений: 261
По умолчанию Проектирование репозитория сотрудников разных типов

У меня есть такая иерархия классов для сотрудников разных типов:

Код:
class AbstractDispatcher;

class AbstractEmployee
{
public:
    virtual ~AbstractEmployee() = default;

    virtual double salary(AbstractDispatcher& dispatcher) = 0;

protected:
    int          id;
    QString  firstname;
    QString  lastname;
    QDate    hire_date;
    double   base_rate;
    int          work_exp;

    AbstractEmployee() = default;
    AbstractEmployee(int id);
    AbstractEmployee(
            int         id,
            QString fname,
            QString lname,
            QDate   hired,
            double  rate,
            int         exp);

    void init(int id);
    void init_work_exp(int id);
};

class Employee : public AbstractEmployee
{
    friend class Dispatcher;
public:
    Employee() = default;
    Employee(int id);
    Employee(int a, QString b, QString c, QDate d, double e, int f)
        : AbstractEmployee(a, b, c, d, e, f) {}

    double salary(AbstractDispatcher& dispatcher) override;
    void debug();

private:
    static constexpr double exp_coeff          = 0.03;
    static constexpr double extra_pay_limit = 0.3;
};

class Manager : public AbstractEmployee
{
public:
    Manager() = default;
    Manager(int id);

    double salary(AbstractDispatcher& dispatcher) override;

private:
    static constexpr double exp_coeff          = 0.03;
    static constexpr double extra_pay_limit = 0.4;
    static constexpr double emp_coeff         = 0.005;
};

class Sales : public AbstractEmployee
{
public:
    Sales() = default;
    Sales(int id);

    double salary(AbstractDispatcher& dispatcher) override;
};
Информация о всех сотрудниках содержится в одной таблице, к которой прилинкована связью маня-к-мане таблица должностей,т.к. сотрудники могут двоедушничать. Мне нужно удобным способом получать информацию по каждому сотруднику, в том числе надо реализовать возможность получать общую сумму выплат всем сотрудникам. Я пытаюсь выстроить архитектуру под эту задачу.

Для получения сотрудников создал репозиторий:

Код:
class EmployeeDAO
{
public:
    EmployeeDAO();

    int selectWorkExperience(int id);
};

class EmployeeRepository
{
public:
    EmployeeRepository();

    Employee select(int id);
    void create();
    void update();
    void remove();
};
EmployeeRepository работает только с сотрудниками типа Employee, но не с Manager и Sales. Можно сделать по одному репозиторию для каждого типа сотрудников, но тогда станет много сущностей. Как можно получать из базы сотрудника типа, к которому он относится? Сделать switch по id должности и возвращать интеллектуальный указатель на базовый класс сотрудника?

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

Код:
class Employee : public AbstractEmployee
{
    friend class Dispatcher;
public:
    Employee() = default;
    Employee(int id);
    Employee(int a, QString b, QString c, QDate d, double e, int f)
        : AbstractEmployee(a, b, c, d, e, f) {}

    double salary(AbstractDispatcher& dispatcher) override;
    void debug();

private:
    static constexpr double exp_coeff          = 0.03;
    static constexpr double extra_pay_limit = 0.3;
};
Но аргументов у конструктора слишком много. Это можно как-то отрефакторить?

Как подсчитать сумму выплат всем сотрудникам?

Дополнение. Зарплата Manager и sales расчитывается в зависимости от суммы зарплат их подчиненных. Как впихнуть список подчиненных в классы Manager и Sales и сделать отложенную инициализацию?

Последний раз редактировалось Aoizora; 07.07.2017 в 20:13.
Aoizora вне форума Ответить с цитированием
Старый 07.07.2017, 20:15   #2
alexzk
Форумчанин
 
Регистрация: 12.04.2017
Сообщений: 889
По умолчанию

Хранить ответ из базы, в классе методы типа getID(), которые выдергивают этот ID из ответа базы, т.е. такой разбор все равно где-то будет, почему не сделать его отложенным.
Т.о. все поля класса вообще пропадают - вместо них 1 поле - ответ базы.

Можно пойти далее, совсем все эти классы убрать к черту. Сделать набор шаблонов, которые из ответа базы дают поле. А сущность для хранения - собственно сам ответ. (сотрудник = ответ).
alexzk вне форума Ответить с цитированием
Старый 07.07.2017, 20:20   #3
Aoizora
Заблокирован
 
Регистрация: 11.11.2016
Сообщений: 261
По умолчанию

Цитата:
Сообщение от alexzk Посмотреть сообщение
Хранить ответ из базы, в классе методы типа getID(), которые выдергивают этот ID из ответа базы, т.е. такой разбор все равно где-то будет, почему не сделать его отложенным.
Т.о. все поля класса вообще пропадают - вместо них 1 поле - ответ базы.
Поля пропадут, зато будет куча огромных методов, которые можно было бы запихать в паттерн DAO.

А как это сделать на шаблонах? Хотя бы примерно.
Aoizora вне форума Ответить с цитированием
Старый 07.07.2017, 21:29   #4
alexzk
Форумчанин
 
Регистрация: 12.04.2017
Сообщений: 889
По умолчанию

Цитата:
Сообщение от Aoizora Посмотреть сообщение
Поля пропадут, зато будет куча огромных методов, которые можно было бы запихать в паттерн DAO.

А как это сделать на шаблонах? Хотя бы примерно.
Скажем, шаблоны и/или перегрузка, и/или макросы вам нужны будут вытаскивать тип из БД в тип из С++ ... тут сильно могут облегчить жизнь всякие Variant из Qt / boost. Т.е. С++ он строготипизированый, а БД - нет. Конечно, тут он много зависит, например, какой драйвер БД и т.д. Может быть, это все там уже решено.

Это такая пеленка простых методов где-то в хидере будет....а потом в программе что-то типа

auto id = get<int>(db_resp, "id");

...а можно вообще все в std::tuple завернуть, т.к. это будет прямое отображение на колонки таблицы. Буквально прописали таблицу в БД, сделали
Код:
using Manager = std::tuple<int,int,string,int>;
все)

...можно совсем извратится, сделать какой-нить генератор на скрипт-языке, который читает SQL, и генерит обвертку-классы для С++. Вопщем тут весь вопрос, насколько просто вы хотите вносить изменения в структуру БД, и как много ручных изменений нужно делать в С++.

Последний раз редактировалось alexzk; 07.07.2017 в 21:40.
alexzk вне форума Ответить с цитированием
Старый 07.07.2017, 21:40   #5
Aoizora
Заблокирован
 
Регистрация: 11.11.2016
Сообщений: 261
По умолчанию

Цитата:
Сообщение от alexzk Посмотреть сообщение
Скажем, шаблоны и/или перегрузка, и/или макросы вам нужны будут вытаскивать тип из БД в тип из С++ ... тут сильно могут облегчить жизнь всякие Variant из Qt / boost. Т.е. С++ он строготипизированый, а БД - нет. Конечно, тут он много зависит, например, какой драйвер БД и т.д. Может быть, это все там уже решено.

Это такая пеленка простых методов где-то в хидере будет....а потом в программе что-то типа

auto id = get<int>(db_resp, "id");

...а можно вообще все в std::tuple завернуть, т.к. это будет прямое отображение на колонки таблицы. Буквально прописали таблицу в БД, сделали
Код:
using Manager = std::tuple<int,int,string,int>;
все)
Хм, но как сделать проверку, что возвращается, например, именно Manager? Ведь надо проверять поле таблицы с id должности, которая связана через таблицу связи с таблицей должностей. А тут мы просто говорим, что нечто, вытащенное из БД, это Manager, никак это не проверяя.
Aoizora вне форума Ответить с цитированием
Старый 07.07.2017, 21:41   #6
alexzk
Форумчанин
 
Регистрация: 12.04.2017
Сообщений: 889
По умолчанию

Цитата:
Сообщение от Aoizora Посмотреть сообщение
Хм, но как сделать проверку, что возвращается, например, именно Manager? Ведь надо проверять поле таблицы с id должности, которая связана через таблицу связи с таблицей должностей. А тут мы просто говорим, что нечто, вытащенное из БД, это Manager, никак это не проверяя.
..можно совсем извратится, сделать какой-нить генератор на скрипт-языке, который читает SQL, и генерит обвертку-классы для С++. Вопщем тут весь вопрос, насколько просто вы хотите вносить изменения в структуру БД, и как много ручных изменений нужно делать в С++.

...да, не проверяя, т.е. это уже ручная работа, при внесении изменений. В Qt это через варианты решено. Я еще к ним макросы клеил с пропертями, типа так (фрагменты)

Код:
#define FIELD(NAME,TYPE) TYPE get##NAME(){return luavm::variantTo<TYPE>(values[QString(#NAME).toLower()]);} \
    void set##NAME(const TYPE& v){values[QString(#NAME).toLower()] = v; emit recordModified(shared_from_this());} \
    Q_PROPERTY(TYPE NAME READ get##NAME WRITE set##NAME STORED true)


class DBReleaseRecord : public QObject, public std::enable_shared_from_this<DBReleaseRecord>
{
    Q_OBJECT
static DBReleaseRecordPtr newRecord(const QSqlRecord& rec);
.....

 FIELD(StrID, QString) //1 вот тут название точно соотв. названию в БД
    FIELD_DATE(ShootingDate) //3

    FIELD(RPath, QString) //4 
    FIELD(PPath, QString) //5

Код:
QVariant DBReleaseRecord::getFieldByName(const QString &field) const
{
    return values.at(field);
}

QVariant DBReleaseRecord::getFieldValue(const QString &name) const
{
    QVariant value;
    const QMetaObject* metaObject = this->metaObject();
    int index = metaObject->indexOfProperty(name.toLatin1().data());
    if (index > -1)
        value = metaObject->property(index).read(this);
    return value;
}

void DBReleaseRecord::setFieldValue(const QString &name, QVariant value)
{
    const QMetaObject* metaObject = this->metaObject();
    int index = metaObject->indexOfProperty(name.toLatin1().data());
    if (index > -1)
        value = metaObject->property(index).write(this, value);
}

Последний раз редактировалось alexzk; 07.07.2017 в 21:46.
alexzk вне форума Ответить с цитированием
Старый 07.07.2017, 21:46   #7
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,330
По умолчанию

https://ru.wikipedia.org/wiki/ORM
waleri вне форума Ответить с цитированием
Старый 07.07.2017, 21:50   #8
Aoizora
Заблокирован
 
Регистрация: 11.11.2016
Сообщений: 261
По умолчанию

Цитата:
Сообщение от waleri Посмотреть сообщение
В C++ с ОРМ все плохо.
Aoizora вне форума Ответить с цитированием
Старый 07.07.2017, 21:56   #9
alexzk
Форумчанин
 
Регистрация: 12.04.2017
Сообщений: 889
По умолчанию

...у меня сейчас, для подобных задач, где нужна рефлексия, доминирует идея такая: прикрепрялем к С++ Lua. Набор шаблонов для удобного луа - с++ приведения и проверки типа есть.
А дальше задачу решаем в луа. Т.о. много че решается - сохранение проекта, конфиги, базы данных - все это можно представить как луа код, а потом просто прогнать его через интерпретатор и получить ответ в С++.
alexzk вне форума Ответить с цитированием
Старый 08.07.2017, 13:35   #10
Aoizora
Заблокирован
 
Регистрация: 11.11.2016
Сообщений: 261
По умолчанию

>auto id = get<int>(db_resp, "id");

Что такое db_resp? Синглтон, хранящий соединение?

Пытаюсь написать такой шаблон, который бы возврщал атрибут для данного работника.

Код:
template <typename ReturnType>
ReturnType get(const QString &field, int id)
{
    QSqlQuery query;
    QString sql = "SELECT :field FROM employee WHERE id = :id";

    query.prepare(sql);
    query.bindValue(":field", field);
    query.bindValue(":id", id);

    query.exec();

    return static_cast<ReturnType>(query.value(0));
}
Первое. Тут требуется id, не очень удобно.
Второе. Как кастить QVariant в ReturnType?

Последний раз редактировалось Aoizora; 08.07.2017 в 13:57.
Aoizora вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Проектирование классов для расчета зарплаты сотрудников разных типов Aoizora C/C++ Базы данных 1 17.06.2017 19:36
Открытие разных типов файлов!!!! mikisss Помощь студентам 10 11.06.2014 12:13
Вывод профайлов разных типов Krasi PHP 6 21.07.2010 18:44
произведение разных типов Асхат Microsoft Office Excel 2 23.04.2010 01:02
Перевод переменных разных типов LeoN Общие вопросы Delphi 3 23.03.2007 00:15