我正在使用抽象基类为我的所有类添加日志记录功能。它看起来像这样:
class AbstractLog
{
public:
virtual ~AbstractLog() = 0;
protected:
void LogException(const std::string &);
private:
SingletonLog *m_log; // defined elsewhere - is a singleton object
};
LogException()
方法将文本写入SingletonLog
对象中定义的日志文件,然后抛出异常。
然后我将它用作所有后续类的基类(在数百个库/ DLL中可能有数百/数千个这样的类)。
这允许我在通常抛出异常的任何地方调用LogException()
。
我的问题是这是否是一个好的设计/实践。
P.S。:我正在使用继承来简单地为我的所有类添加功能,而不是实现任何类型的多态。最重要的是,我所有类与AbstractLog
类之间存在关系的概念是有争议的(每个类都是一个可记录的对象?嗯,是的,我想它们是,但只是因为我'他们这样做了。)
答案 0 :(得分:3)
你建议使用什么,我认为更好的是创建日志类(继承自此接口)并使用它作为一种方式组合(使用接口)而不是继承 - 组合是逻辑类和日志类之间较弱的连接。最好的做法是越少越好。另外一个好处是,您可以随时扩展日志功能,而无需修改业务逻辑。
关于这个单身人士,也许代理模式更好?
希望,我帮助了:)。
答案 1 :(得分:2)
这对我来说似乎有些过分。并且继承应该表达是的关系。因此,在您的情况下,您可以说项目中的每个类都是记录器。但实际上你只需要一个记录器,因此单件。
在我看来, singleton 使您有机会避免从记录器类继承并将记录器类存储为成员。您可以在每次需要时轻松抓住单身人士。
class Logger
{
public:
void error(const std::string& msg);
void warning(const std::string& msg);
void exception(const std::string& msg);
// singleton access
static Logger& log()
{
// singleton
static Logger logger;
return logger;
}
};
class Unrelated
{
public:
void func()
{
// grab the singleton
Logger::log().exception("Something exceptional happened");
}
};
我想我说通过记录器的单个静态方法获取单例似乎不那么突兀,而不是让项目中的每个类都继承自logger类。
答案 2 :(得分:0)
除了朋友关系之外,继承是可以用C ++表达的最强耦合。
鉴于louse耦合的原理,高内聚性,我认为如果你只是想为一个类添加功能,最好使用更宽松的耦合类型。
由于logger是一个单独制作LogException,因此自由函数是实现相同目标的最简单方法,而不需要与继承相结合。
答案 3 :(得分:0)
我不确定通过使用自由函数记录异常来获得任何收益。如果你有一个免费的LogException函数,那么你也需要为LogError和LogWarning提供免费函数(复制Galik的功能),Logger对象可以是在文件范围定义的非本地静态对象,在启动时实例化或者您需要另一个自由函数(类似于Logger方法并从所有其他日志记录函数调用),其中Logger对象将是第一次调用该方法时实例化的本地静态对象。对我来说,Logger对象一次性捕获所有这些。
需要考虑的另一点是性能 - 如果您将使用静态日志记录对象拥有大量对象,那么该对象可能会对写入日志文件和主要业务的高写入率感到困惑逻辑可能会在文件写入时被阻止。可能值得考虑将错误和警告消息添加到Logger对象内的队列,然后让一个单独的工作线程通过队列并执行实际的文件写入。然后,您需要在写入和读取此内部队列时需要线程保护锁。
此外,如果您使用的是静态日志记录对象,那么您需要确保包括DLL在内的整个应用程序是单线程的,否则您可能会让多个线程同时写入同一个文件并且您需要放置线程即使您没有使用内部队列,保护也会锁定到Logger中。
答案 4 :(得分:0)
" ...使用它作为我所有后续类的基类......" - " ...问题是这是否是好的设计/实践。"
不,不是。
您通常希望避免的一件事是多重继承问题。如果应用程序中的每个类都派生自某个实用程序类,然后是另一个实用程序类,然后是另一个实用程序类......那么您就会明白这一点。
此外,你表达了错误的东西 - 你的课程实际上很少是专业的记录器,对吧? (这就是继承意味着 - 是。)
既然你提到了DLL ......你知道C ++ DLL中隐含的问题,即ABI的脆弱性吗?您基本上是强制客户端使用完全相同的编译器和-version。
如果您的架构导致(字面上)数百个库,那么无论如何都会出现问题。