2014-11-30 4 views
3

Мое приложение обрабатывает различные сообщения и хранит их в базе данных. Сейчас я использовал следующую конструкцию: классУлучшенный дизайн для абстракции Db с наследованием

База данных:

class DbObject 
{ 
public: 
    // read/write object members from/to DB 
    virtual void readFromDb() = 0; 
    virtual void writeToDb() = 0; 

    // Other stuff, db connection etc. 
    void doDbStuff(); 
} 

Базовый класс для сообщений:

class BaseMsg 
{ 
public: 
    // read/write object members from/to DB 
    virtual std::string toXml() = 0; 
    virtual void fromXml(const & std::string s) = 0; 
} 

типы сообщений A, B и т.д.

class MsgA : public BaseMsg, DbObject 
{ 
public: 
    std::string toXml(); 
    void fromXml(const & std::string s); 

    void readFromDb(); 
    void writeToDb(); 
} 

Этот дизайн работает хорошо, каждое обработанное сообщение получает свой собственный объект, может быть записано в XML, прочитано из XML, сохранено и прочитано в/из m база данных с конкретными сообщениями (реализована в MsgA).

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

Обычно у меня был бы базовый класс для доступа к базе данных и дочерние классы для каждого типа базы данных. Но с нынешним дизайном невозможно, потому что я не хочу иметь класс MsgADatabase1 и класс MsgADatabase2 и т. Д.

Есть ли какой-либо шаблон дизайна, где я мог бы сохранить свой текущий дизайн в принципе, но скрыть используемый в настоящее время тип базы данных за каким-то уровнем абстракции?

+2

Все базы данных имеют функциональные возможности INSERT, QUERY, DELETE и UPDATE. Просто создайте абстрактный базовый класс, который поддерживает эти четыре (и возможные другие) операции, и дочерние классы, которые реализуют эти операции с конкретной базой данных. Затем используйте указатель на базовый класс в классе 'DbObject' и используйте его для выполнения операций с базой данных. –

+1

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

ответ

3

1. Сначала подумал бы увидеть DbOject в качестве адаптера.

В соответствии с Банды четырех, то adapter должен предложить целевой интерфейс для адаптированного объекта (конкретный объект базы данных) либо с помощью множественного наследования или композиции.

В контексте вашего множественного наследования этот дизайн наложит то, что на каждый DbObject вы наследуете сообщение, его конструктор создаст одну-единственную ссылку с конкретным проектом DB. Но как конструктор может знать, какой конкретный класс db создать?

2. Следующая мысль: объединить этот адаптер с абстрактным заводом

Самыми естественным узором для создания зависимого объекта базы данных, конкретного экземпляр абстрактных зависят от базы данных obect будет использовать в abstract factory.

В сочетании с адаптером, вы бы следующий сценарий:

  • при запуске, виртуальный завод (класс Database) объект получает инстанцированный с конкретной базой данных зависимого предприятием (class DatabaseBrandA : public Database)
  • виртуальных фабрика предоставляет функцию для создания DbIndependentObject.Бетонный завод реализует эту функцию, предоставляя свои собственные конкретные объекты (class DbBrandAdependentObject : public DbIndependentObject)
  • Каждый раз, когда создается сообщение, базовый адаптер DbObject запрашивает виртуальную фабрику для создания нового объекта. Таким образом, это относится к DbIndependentObject реализуемым в DbBrandAdependentObject)

Однако, я не знаю, если содержание вашего DbObject действительно настолько богато, что он нуждается в один к одному отношениям с конкретным объектом базы данных. Является ли такая сложная модель не излишней?

3.Final вывод: адаптер в сочетании с шаблоном проектирования прокси

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

Если ваш текущий код разработан таким образом, что DbOject инкапсулирует все, что связано с базой данных, просто нужно proxy к этой базе данных.

Это будет работать по следующему сценарию:

  • при запуске, абстрактную базу данных (класс Database) объект получает экземпляр с конкретной базой данных (class DatabaseBrandA : public Database)
  • Каждый раз, когда создается сообщение, то base DbObject действует как прокси-сервер, ссылающийся на объект базы данных.
  • Каждый раз, когда необходимо выполнить операцию с базой данных, DbObject действует как адаптер для сообщения, предоставляя необходимые функции чтения записи.
+1

Спасибо за ваши мысли. Я думаю, что вариант 2. кажется хорошим решением, но я должен проверить, может ли реализация быть упрощена до варианта 3. В классах сообщений существует много связанных с db реализаций, я должен проверить, действительно ли это специфичный для каждого типа сообщения или может быть упрощен в базовом классе, – Simon

2

Вы можете реализовать шаблон адаптера и сохранить источник данных (любой БД или другой источник данных) в качестве внешнего объекта для уменьшения связи.

Смежные вопросы