Читатели / писатели и отделенные постоянство производных классов - PullRequest
0 голосов
/ 06 октября 2010

Я рефакторинг кучу старого кода. Моя основная задача - отделить поведение от базы данных. Текущая реализация напрямую обращается к базе данных, что затрудняет тестирование и делает такие вещи, как реализация слоев кэширования и т. Д. До этого момента я с большим успехом использовал комбинацию инверсии зависимостей и читателей / писателей, то есть достиг некоторых из наших более сложных типов.

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

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

class User
{
public:
    std::string
    name() const
    {
        return m_name;
    }

    void
    name(const std::string& name)
    {
        m_name = name;
    }

private:
    std::string m_name;
}

class EmailUser : User
{
public:
    std::list<std::string>
    emails() const
    {
        return m_emails;
    }

    void
    emails(const std::string<std::string>& emails)
    {
        m_emails = emails;
    }

private:
    std::set<std::string>   m_emails;
}

class UserWriter
{
public:
    virtual void
    write(User& user) = 0;
}

class DBUserWriter : UserWriter
{
public:
    void
    write(User& user)
    {
        SQLExecute("SOME SQL UPDATE STMT %s", user.name());
    }
}

class DBEmailUserWriter : UserWriter
{
public:
    void
    write(User& user)
    {
        m_baseUserWriter.write(user);
        SQLExecute("SOME SQL UPDATE STMT %s", user.email.front());
    }
private:
    DBUserWriter    m_baseUserWriter;
}

1 Ответ

3 голосов
/ 06 октября 2010

Вот пример использования реализации двойной отправки, указанной на странице википедии:

#include <iostream>
using namespace std;

class Writer;

class User
{
public:
    std::string name() const { return m_name; }
    void name(const std::string& name) { m_name = name; }
    virtual void accept(Writer & writer) const;

private:
    std::string m_name;
};

class EmailUser : public User
{
public:
    std::string email() const { return m_email; }
    void email(const std::string& email) { m_email = email; }
    virtual void accept(Writer & writer) const;

private:
    std::string m_email;
};

class Writer
{
public:
  void process(const User& user) { user.accept(*this); }
  virtual void write(const User& user) { cout << user.name() << endl; }
  virtual void write(const EmailUser& user) { cout << user.email() << endl; }
};

class SubWriter : public Writer
{
public:
  void process(const User& user) { user.accept(*this); }
  void write(const User& user) { cout << "[" << user.name() << endl; }
  void write(const EmailUser& user) { cout << "[" << user.email() << endl; }
};

void User::accept(Writer & writer) const { writer.write(*this); }
void EmailUser::accept(Writer & writer) const { writer.write(*this); }

int main()
{
  User u;
  EmailUser eu;
  Writer w;
  SubWriter s;

  u.name("Hugo Peixoto");
  eu.email("hugo.peixoto@gmail.com");

  w.process(u);
  w.process(eu);

  s.process(u);
  s.process(eu);

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