Привет!
не могу найти примера того, как нужно использовать подклассы Singlton'а Мейерса.
суть задачи проста: нужен абстрактный класс логгера, и несколько его реализаций - для файловой системы, для БД, для консоли и т.д. Конечно, сам Логгер на всю программу должен быть в ед. экземпляре.
Вот чего-то я запутался в этих трех соснах. Help me, please!
как-то непонятно, чего ты хочешь. singleton всегда имеет один экземпляр. что значит "несколько реализаций"?
я планирую сделать так:
наследовать от QObject (юзаю Кьют) некий базовый подкласс (от которого наследовать остальные классы), в котором объявлен логгер, и потом где-то как-то выбирать конкретный логгер, используемый приложением:
// BASE.H
class BASE : public QObject
LOGGER * logger;
...
};
// BASE.CPP
BASE::BASE(QObject) {
switch(log_type){
case 0: logger = FILE_LOGGER::get_instance();
case 1: logger = DB_LOGGER::get_instance();
case 2: logger = CONSOLE_LOGGER::get_instance();
}
...
logger->log("BINGO!");
};
ты пытаешься применить паттерн фабрики к синглтону. про паттерны можешь почитать здесь: http://www.wiki.crossplatform.ru/index.php/Design_Patterns
посмотри "Фабричный метод". там примерно то, что ты пытаешься изобразить, насколько я понимаю.
именно!
так я и читаю книжку по паттернам, отсюда и мысли о таких решениях приходят.
по-отдельности разобрал и тот, и другой паттерн, как их совместить - пока не понимаю.
Собственно, я не могу понять: все классы (LOGGER & FILE_LOGGER, DB_LOGGER, ...) должны быть реализованы как Singleton, или не все? если FILE_LOGGER, наследует LOGGER и в классе BASE я использую интерфейс класса LOGGER, значит надо прописать в нем виртуальную ф-ию log(QString), для того, что бы переопределить её в FILE_LOGGER. Но если класс LOGGER является Singlton'ом, то значит ф-ия log() должна быть static...вот какие противоречия роятся у меня в голове
решил!
// .H
#ifndef CLASS1_H
#define CLASS1_H
#include <iostream>
enum LOG_TYPE {LOG_C1 = 0, LOG_C2 = 1};
class class1;
class c1Dest
{
class1 * _inst;
public:
~c1Dest();
void init(class1 * p);
};
class class1
{
static class1 * __inst;
static c1Dest dest;
static LOG_TYPE type;
protected:
class1(){}
class1(const class1&);
class1& operator=(class1&);
~class1(){}
friend class c1Dest;
public:
static class1& instance();
virtual void echo();
};
class class2 : public class1
{
public:
void echo();
};
#endif // CLASS1_H
// .CPP
#include "class1.h"
LOG_TYPE class1::type = LOG_C1;
class1 * class1::__inst = 0;
c1Dest class1::dest;
c1Dest::~c1Dest(){
delete _inst;
}
void c1Dest::init(class1 *p){
_inst = p;
}
class1& class1::instance(){
if (!__inst){
switch (type){
case LOG_C1: __inst = new class1; break;
case LOG_C2: __inst = new class2; break;
}
dest.init(__inst);
}
return *__inst;
}
void class1::echo(){
std::cout << "class1::echo() " << this << std::endl;
}
void class2::echo(){
std::cout << "class2::echo() " << this << std::endl;
}
Вот еще один вариант реализации с помощью шаблонов:
template<class T>
class SingleTonePattern {
public:
static T& getInstance() {
static T instance;
return instance;
}
virtual void echo() = 0;
};
class CustomSingleTone : public SingleTonePattern<CustomSingleTone>
{
friend class SingleTonePattern<CustomSingleTone>;
private:
CustomSingleTone() {}
public:
virtual void echo() {
qDebug() << "ECHO!!";
}
};
CustomSingleTone &st = SingleTonePattern<CustomSingleTone>::getInstance();
st.echo();
насчёт решения с классами - какое-то оно странное. честно говоря, непонятно, как это будет использоваться. подумай ещё. это полезно. и обязательно попробуй использовать свои классы, без этого ты не поймёшь потенциальных минусов своего решения.
#ifndef SOME_HEADER_NAME
#define SOME_HEADER_NAME
....
<код>
....
#endif
не совсем понятно, зачем этот огород?
qDebug() все эти вещи решает вполне прозрачно, или любой другой подобный объект.
Вывод всегда можно направить в нужное место.
#ifndef SOMEHEADER_H
#define SOMEHEADER_H
#include <otherheader.h>
class SomeClass
{
};
#endif //SOMEHEADER_H
Постараюсь ответить по-порядку )
Iron Bug, спасибо за пояснение насчет __var. В приложениях такие имена никогда не использую, это был тест на скорую руку, что бы проверить независимость переменных с одним и тем же именем в разных классах. почему-то меня взяли сомнения на этот счет это было самое простое и быстрое решение. но теперь есть причина тем более не делать этого.
да, согласен, решение с классами действительно получилось довольно странным. я его не буду использовать, но кое на чем хочу остановиться: как мне показалось, вы (и Iron Bug, и wiz29) не поняли моего вопроса насчет развязки хедеров. Дело в том, что нет возможности вынести class2 в отдельный файл - он зависит от class1, который в свою очередь использует class2 в своей функции instance(). Получаются перекрестные ссылки, и я не нашел решения, как их развязать. Что скажете, сможете предложить решение? или это я не понял ваших комментариев?
class Class1 {
Class1 * instance();
...
}
#include "class1.h"
#include "class2.h"
Class1 * Class1::instance() {
...
}
#include "class1.h"
class Class2 : public Class1 { ...}
#include "class2.h"
...
в случае, если перекрёстные ссылки всё-таки есть (это должны быть именно ссылки, а не объекты класса), то стандартное решение состоит в использовании предварительной декларации класса:
class ClassB; // предварительная декларация класса ClassB
class ClassA {
ClassB *ptrB;
};
class ClassB {
ClassA *ptrA;
ClassA A; // после полного определения класса мы можем использовать не только указатели, но и объекты класса
};
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)