如何在 C++ 中实现干净的架构组件边界?

How to implement clean architecture component boundaries in c++?

我正在阅读 Robert C. Martin 的 Clean Architecture,我想将书中的知识应用到我的 C++ 程序中。然而,我不明白的一件事是接口边界应该如何工作。

"inner layers"(业务规则)不应该知道任何关于外层的信息。意思是红线以上的东西不应该知道下图中红线下面的东西。

但是如果业务规则使用 C++ 接口(纯抽象 class)与数据库对话(下图中的数据库接口),它们是否必须包含对实现的引用header 在 "Database Access/Database" 模块中,因为无法实例化抽象基础 class?那岂不是违背了业务规则不应该知道任何外层的原则?

在 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;
};

依赖于数据库的class可以依赖于指向抽象基class的拥有指针。它不需要知道任何关于实现的信息:

struct BusinessRules {
    std::unique_ptr<DatabaseInterface> db; // reference
    BusinessRules(std::unique_ptr<DatabaseInterface>);
    /* stuff using the database interface */
};

虽然你不能直接实例化它,但你可以让另一个 class 继承接口,并且你可以将具体 class 的实例传递给需要指针的消费者抽象 class 接口:

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

标准库与 istream. istream has a bunch of methods which act on top of an lower-level streambuf member. streambuf is an abstract interface whose implementations perform I/O access (to stdin, files, strings 等类似。

虽然其中的 none 直接 与 Clean Architecture 相关,但您可以通过这种方式使组件的实现独立于它们的依赖项。