我正在阅读Robert C. Martin的Clean Architecture,我想将本书中的知识应用于我的C ++程序。但是,我不明白的一件事是接口边界应该如何工作。
“内层”(业务规则)不应了解有关外层的任何信息。在下图中,红线上方的内容应该不了解其下方的内容。
但是,如果业务规则使用C ++接口(纯抽象类)与数据库进行通信(下图中的数据库接口),则不必在“数据库访问/数据库”模块,因为无法实例化抽象基类?难道这不违反业务规则不应该了解任何有关外层的原则吗?
用c ++做到这一点的正确方法是什么?
图像:来自Clean Architecture的图17.2
C ++中的纯虚拟接口大致类似于C#或Java这样的托管语言中的接口:
struct DatabaseInterface {
virtual ~DatabaseInterface();
virtual std::string get(std::string key) = 0;
virtual void put(const std::string& key, const std::string& value) = 0;
};
依赖于数据库的类可以依赖于指向抽象基类的指针。它不需要了解任何实现:
struct BusinessRules {
std::unique_ptr<DatabaseInterface> db; // reference
BusinessRules(std::unique_ptr<DatabaseInterface>);
/* stuff using the database interface */
};
虽然您不能直接实例化它,但是您可以让另一个类继承该接口,并且可以将具体类的实例传递给需要一个指向抽象类接口的指针的使用者:
struct SpecificDatabaseAccess: public DatabaseInterface {
SpecificDatabaseAccess(const std::string& connectionString);
std::string get(std::string key) override;
void put(const std::string& key, const std::string& value) override;
};
/* ... */
// dependency injection through the constructor
auto db = std::make_unique<SpecificDatabaseAccess>("...");
auto rules = BusinessRules(std::move(db));
尽管标准库不是Clean Architecture的一个杰出示例,但它与istream
的功能类似。 istream
有许多在较低级别istream
成员之上起作用的方法。 streambuf
是一个抽象接口,其实现执行I / O访问(到stdin,streambuf
,streambuf
等)。