使用继承添加功能

Using inheritance to add functionality

本文关键字:功能 添加 继承      更新时间:2023-10-16

我正在使用一个抽象基类为我的所有类添加日志记录功能。它看起来像这样:

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()

我的问题是这是否是一个好的设计/实践

附言:我使用继承只是为了给我的所有类添加功能,而不是实现任何类型的多态性。最重要的是,我的所有类与AbstractLog类都有is-a关系的概念是有争议的(每个类都是一个可记录的对象?嗯,是的,我想它们是,但只是因为我已经这样做了)。

你的建议是可行的,我认为最好是创建日志类(从这个接口继承),并将其用作组合(使用接口)而不是继承-组合是逻辑类和日志类之间较弱的连接。最好的做法是班级越少越好。额外的好处是,您可以随时扩展日志功能,而无需修改业务逻辑。

关于这个singleton,也许代理模式更好?

希望,我帮助了:)

这对我来说似乎有些过头了。继承应该表达是一种关系。因此,在您的案例中,您有点说项目中的每个类都是记录器。但实际上,您只需要一个记录器,因此需要singleton

在我看来,singleton为您提供了避免从记录器类继承和将记录器类存储为成员的机会。你可以在每次需要的时候简单地获取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");
    }
};

我想我是说,通过记录器的单个静态方法获取singleton似乎比让项目中的每个类从记录器类继承更不突兀。

我不确定您是否通过使用免费函数来记录异常而获得了任何好处。如果您有一个LogException免费函数,那么假设您还需要LogError和LogWarning的免费函数(以复制Galik的功能),Logger对象将是在文件范围内定义并在启动时实例化的非本地静态对象,或者您需要另一个免费函数(类似于Logger方法并从所有其他日志记录函数调用),其中Logger对象将是第一次调用该方法时实例化的本地静态对象。对我来说,Logger对象一次就巧妙地捕捉到了这一切。

另一个需要考虑的问题是性能——如果有大量对象都使用静态日志记录对象,那么该对象可能会在向日志文件的高写入率方面遇到困难,并且您的主要业务逻辑可能会在文件写入时受阻。可能值得考虑的是,将错误和警告消息添加到Logger对象内的队列中,然后让一个单独的工作线程穿过队列并执行实际的文件写入。然后,在对该内部队列进行写入和读取时,需要使用线程保护锁。

此外,如果您使用的是静态日志记录对象,则需要确保包括DLL在内的整个应用程序都是单线程的,否则您可能会让多个线程同时写入同一文件,并且即使您没有使用内部队列,也需要将线程保护锁放入Logger中。

除了朋友关系之外,继承是C++中可以表达的最强耦合。

考虑到louse耦合的原理,即高内聚性,我认为如果你只想为类添加功能,最好使用更松散的耦合类型。

由于记录器是一个单例,因此将LogException作为一个免费函数是实现相同目标的最简单方法,而无需与继承进行强耦合。

"…将其用作所有后续类的基类…"--"…问题是这是否是好的设计/实践。"

不,不是。

您通常希望避免的一件事是多个继承问题。如果应用程序中的每个类都派生自某个实用程序类,然后另一个实用程序类和另一实用程序类别。。。你明白了。

此外,你表达了错误的东西——你的类中很少有是专门的记录器,对吧?(这就是继承的含义——。)

既然你提到了DLL。。。您知道C++DLL中隐含的问题,即ABI的脆弱性吗?您基本上是在强迫客户端使用相同的编译器和版本。

如果您的体系结构导致(从字面上)数百个库,那么无论如何都会出现一些非常错误的地方。