使用继承添加功能
Using inheritance to add functionality
我正在使用一个抽象基类为我的所有类添加日志记录功能。它看起来像这样:
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的脆弱性吗?您基本上是在强迫客户端使用相同的编译器和版本。
如果您的体系结构导致(从字面上)数百个库,那么无论如何都会出现一些非常错误的地方。
- 设计模式,以避免不必要地添加抽象函数以适应新功能
- 在大括号内添加语句会更改代码功能?
- 如何在数据库程序中添加"reduce the quantity of an item"功能?
- 如何在控制台应用程序中添加滚动功能以显示更大的输入
- C++ 添加编译器警告,以错误使用自定义打印/日志功能
- C++要在其中添加接口功能的类层次结构
- 在 C++ 中向多态树添加功能
- 如何将搜索功能添加到数组中
- 如何为内置类型添加成员功能,例如C 中的整数
- 疯狂(乘,添加,划分)哈希功能如何起作用
- 将功能参数添加到向量
- 使用指针在功能中的数组中添加/删除元素
- 将功能添加到默认复制构造函数中
- C 将类成员功能添加到地图中
- 如何将搜索功能添加到WXWIDGET C 中的TextCtrl
- 我应该如何将另一个类的方法的功能添加到我的当前类中?
- 为气泡排序功能添加计数器
- 无法为包装器功能添加完美的转发
- 当您下载其他库并将其功能添加到C ++程序中时,您是否能够在另一台PC上运行您的软件(没有库)?
- 如何在gcc中保留命令行选项,但为某些功能添加更多优化标志