我有一个单例类,用于在我的Qt项目中进行日志记录。在除单例对象之外的每个类中,都有指向该单例对象的指针和连接到所述单例对象中的写入槽的信号。不管哪个类想要写日志信息,只要发出这个信号。信号是排队的,所以线程是安全的。
请从面向对象的角度来评论这种方法,谢谢。
=============================================================================================编辑1:谢谢你所有的申请,倾听相反的意见总是一个很大的学习。
让我更多地解释一下我的方法以及到目前为止我在代码中做了什么:正如MikeMB指针一样,单例类有一个像get_instance()这样的静态函数,它返回对该单例的引用。我将其存储在每个类的构造函数中的一个本地指针中,因此它将在构造函数返回后销毁。它便于检查是否有空指针,并使代码更具可读性。我不喜欢这样的东西:
if(mySingletonClass::gerInstance() == NULL) { ... }
connect(gerInstance(), SIGNAL(write(QString)), this, SLOT(write(QString)));因为它比这个贵:
QPointer<mySingletonClass> singletonInstance = mySingletonClass::getInstance();
if(singletonInstance.isNull) { ... }
connect(singletonInstance, SIGNAL(write(QString)), this, SLOT(write(QString)));两次调用一个函数比从ASM的角度创建一个局部变量要昂贵得多,因为它需要推送、pop和返回地址计算。
这是我的单身班级:
class CSuperLog : public QObject
{
Q_OBJECT
public:
// This static function creates its instance on the first call
// and returns it's own instance just created
// It only returns its own instance on the later calls
static QPointer<CSuperLog> getInstance(void); //
~CSuperLog();
public slots:
void writingLog(QString aline);
private:
static bool ready;
static bool instanceFlag;
static bool initSuccess;
static QPointer<CSuperLog> ptrInstance;
QTextStream * stream;
QFile * oFile;
QString logFile;
explicit CSuperLog(QObject *parent = 0);
};我在main()的开头调用getInstance(),因此当它们需要记录重要信息时,请确保它们能够立即为其他类读取。
MikeMB:
Your approach is making a middle man sitting in between, it makes the path of the logging info much longer because the signals in Qt are always queued except you make direct connection. The reason why I can't make direct connection here is it make the class non-thread-safe since I use threads in each other classes. Yes, someone will say you can use Mutex, but mutex also creates a queue when more than one thread competing on the same resource. Why don't you use the existing mechanism in Qt instead of making your own?谢谢你们所有的帖子!
=========================================================
编辑2:
给Marcel Blanck:
你能解释一下你的静态Logger工厂的方法吗?谢谢。
发布于 2013-11-24 13:31:31
我会考虑将记录器应该是唯一的这一事实与其他类如何获得记录器类的实例分开。
创建和获取记录器实例可以在某种类型的工厂中处理,该工厂内部封装其结构,并在需要时只生成一个实例。
然后,其他类获取记录器实例的方式可以通过依赖注入或上述工厂上定义的静态方法来处理。使用依赖项注入,首先创建记录器,然后将其注入创建后的其他类。
发布于 2013-11-24 14:09:15
我不太喜欢单身人士,因为使用他们总是不干净的。我甚至读过一些职务说明,上面写着“了解设计模式,同时又知道Singleton不是一个可以使用的人”。Singleton导致依赖地狱,如果您想要更改为完全不同的日志记录方法(用于测试或生产的mabe),同时不破坏旧的日志记录方法,则需要进行大量更改。
该方法的另一个问题是信号的使用。是的,免费获得线程的灵活性,并且不要中断代码的执行,但是.
我会直接打印。也许您可以有一个返回记录器的静态Logger工厂,这样您就可以在每个线程中有一个记录器对象(内存影响仍然很小)。或者您有一个使用信号量的线程保存,并且具有一个静态接口。在这两种情况下,记录器应该通过一个接口使用,以便以后更加灵活。
还请确保直接打印您的方法。即使printf在打印之前也会写到缓冲区中,而且每次都需要刷新它,否则在恶劣的情况下可能永远找不到崩溃,如果您在寻找它们的话。
只是我的两分钱。
发布于 2013-11-24 13:30:36
单例通常有一个静态函数,如get_instance(),它返回对该单例的引用,因此不需要在每个对象中存储指向该单例的指针。
此外,让每个对象将其日志信号连接到日志对象本身的日志槽没有任何意义,因为这使得项目中的每个类都依赖于日志记录类。相反,让类只发出带有日志信息的信号,并在更高级别的某个中心建立连接(例如,在主函数中设置系统时)。因此,您的其他类不必知道谁在监听(如果有的话),您可以轻松地修改或替换您的日志记录类和机制。
顺便说一句:已经有相当先进的日志库了,所以您应该了解是否可以使用其中的一个,或者至少是如何使用它们,并根据您的需要调整这个概念。
==========================
编辑1(对QtFan编辑1的响应):
抱歉,显然我错过了您的理解,因为我认为指针将是类成员,而不仅仅是构造函数中的局部变量,这当然很好。
让我也澄清一下我在更高层次上建立连接的意思:这完全是为了你在哪里建立连接,也就是你把线路放在哪里。
connect(gerInstance(), SIGNAL(write(QString)), this, SLOT(write(QString)));我建议将它放在类之外的某个地方,例如在主函数中。因此,伪代码看起来如下所示:
void main() {
create Thread1
create Thread2
create Thread3
create Logger
connect Thread1 signal to Logger slot
connect Thread2 signal to Logger slot
connect Thread3 signal to Logger slot
run Thread1
run Thread2
run Thread3
}这样做的好处是,您的类不必知道您正在使用的记录器的类型,以及是否只有一个、多个或根本没有一个记录器。我认为关于信号和插槽的整个想法是,发射对象不需要知道它的信号是在哪里处理的,接收类不需要知道信号来自哪里。
当然,这只有在程序运行时不动态创建对象/线程的情况下才是可行的。如果您想在创建对象的过程中进行日志记录,它也不起作用。
https://stackoverflow.com/questions/20174665
复制相似问题