栈分配RAII对象vs DI原则
Stack allocated RAII objects vs DI principle
在c++中,我经常使用raii风格的对象使代码更可靠,并在堆栈上分配它们以使代码更性能(并避免bad_alloc)。
但是在堆栈上创建一个具体类的对象违反了依赖倒置(DI)原则,并且阻止了对该对象的模拟。
考虑以下代码:
struct IInputStream
{
virtual vector<BYTE> read(size_t n) = 0;
};
class Connection : public IInputStream
{
public:
Connection(string address);
virtual vector<BYTE> read(size_t n) override;
};
struct IBar
{
virtual void process(IInputStream& stream) = 0;
};
void Some::foo(string address, IBar& bar)
{
onBeforeConnectionCreated();
{
Connection conn(address);
onConnectionCreated();
bar.process(conn);
}
onConnectionClosed();
}
我可以测试IBar::process
,但我也想测试Some::foo
,而不创建真正的连接对象。
我当然可以使用工厂,但它会显著地使代码复杂化,并引入堆分配。
另外,我不喜欢添加Connection::open
方法,我更喜欢构造完全初始化和功能齐全的对象。
我会使Connection
类型为Some
模板参数(或foo
,如果提取它作为一个自由函数),但我不确定这是正确的方式(模板看起来像一个黑魔法对许多人来说,所以我更喜欢使用动态多态性)
您现在正在做的是"强制耦合"RAII类和服务提供者类(如果您想要可测试性,它实际上应该是一个接口)。通过:
- 将
Connection
抽象为IConnection
- 有一个单独的
ScopedConnection
类,在上面提供RAII
void Some::foo(string address, IBar& bar)
{
onBeforeConnectionCreated();
{
ScopedConnection conn(this->pFactory->getConnection());
onConnectionCreated();
bar.process(conn);
}
onConnectionClosed();
}
"我可以使用工厂,但它会显著地使代码复杂化并引入堆分配",我指的是以下步骤:
创建抽象类并从中派生Connection
struct AConnection : IInputStream
{
virtual ~AConnection() {}
};
为Some
添加工厂方法
class Some
{
.....
protected:
VIRTUAL_UNDER_TEST AConnection* createConnection(string address);
};
用智能指针替换堆栈分配的连接
unique_ptr<AConnection> conn(createConnection(address));
要在实际实现和模拟实现之间进行选择,必须注入想要以某种方式构造的实际类型。我推荐的方法是将类型作为可选的模板参数注入。它允许您像过去那样不显眼地使用Some::foo
,但是允许您在测试的情况下交换创建的连接。
template<typename ConnectionT=Connection> // models InputStream
void Some::foo(string address, IBar& bar)
{
onBeforeConnectionCreated();
{
ConnectionT conn(address);
onConnectionCreated();
bar.process(conn);
}
onConnectionClosed();
}
如果您在编译时知道实际类型,我就不会创建工厂和运行时多态性的开销。
相关文章:
- С++ wxWidgets:代码架构,设计原则和模式
- 我需要如何更改我的程序以使用打开/关闭原则?
- 复制赋值函数如何访问另一个对象的私有成员(Stroustroup 原则和实践书)?
- Visual Studio 2017扩展选项卡中的C++核心指导原则检查器丢失
- 是否有一种设计模式或面向对象的基本原则来处理这种共享资源的情况?
- DI 加速 C++14 和动态容器
- 分层状态机涉及哪些原则,以及如何实现基本模型?
- 如何应用注册表模式使"select class depend on input"遵守开放封闭原则?
- 不兼容的操作原则到三元op
- 代码在Visual C ++中无法按预期工作(来自bjarne stroustrup编程和原则书籍2n版本的示例)
- 用坚实的原则用 arduino 写作
- 提升月份的行为的原则是什么?
- C++中的依赖反转(来自 S.O.L.I.D 原则)
- 将 boost-di 与配置文件和共享库一起使用
- Objective-C 块文字语法原则
- [BOOST] .DI装饰器图案
- BST 与 C++ 年的 OOP 原则
- 何时违反单一责任原则
- 在FTDI 2232H迷你模块上使用GPIO输入而不是TDO/DI
- 栈分配RAII对象vs DI原则