简体   繁体   English

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

[英]How to implement clean architecture component boundaries in c++?

I am reading Clean Architecture by Robert C. Martin and I would like to apply the knowledge in the book to my C++ programs.我正在阅读 Robert C. Martin 的 Clean Architecture,我想将书中的知识应用到我的 C++ 程序中。 One thing I don't understand, however, is how the interface boundaries are supposed to work.然而,我不明白的一件事是接口边界应该如何工作。

The "inner layers" (business rules) are not supposed to know anything about outer layers. “内层”(业务规则)不应该知道任何关于外层的信息。 Meaning the things above the red line shouldn't know anything about the things below it in the image below.意思是红线上方的东西不应该知道下图中红线下方的东西。

But if the business rules use an C++ interface (pure abstract class) to talk to the database (the Database Interface in the image below), won't they have to include a reference to the implementation header in the "Database Access/Database" module since an abstract base class cannot be instantiated?但是,如果业务规则使用 C++ 接口(纯抽象类)与数据库(下图中的数据库接口)通信,它们是否不必在“数据库访问/数据库”中包含对实现标头的引用模块,因为抽象基类不能被实例化? And wouldn't that be a violation of the principle that the business rules should'nt know anything about the outer layers?这难道不会违反业务规则不应了解外层的原则吗?

What would be the correct way to to this in c++?在 C++ 中正确的方法是什么?

图 17.2,干净的架构

Image: Figure 17.2 from Clean Architecture图片:图 17.2 来自 Clean Architecture

A pure virtual interface in C++ is roughly analogous to an interface in a managed language like C# or Java: 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;
};

A class depending on a database can depend on an owning pointer to the abstract base class.依赖于数据库的类可以依赖于指向抽象基类的拥有指针。 It doesn't need to know anything about the implementation:它不需要了解有关实现的任何信息:

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

And while you can't instantiate that directly, you can have another class inherit the interface, and you can pass an instance of the concrete class to a consumer which expects a pointer to the abstract class 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));

The standard library does something similar with istream .标准库对istream做了类似的事情。 istream has a bunch of methods which act on top of an lower-level streambuf member. istream有一堆方法,它们作用于较低级别的streambuf成员之上。 streambuf is an abstract interface whose implementations perform I/O access (to stdin, files , strings , etc). streambuf是一个抽象接口,其实现执行 I/O 访问(对 stdin、文件字符串等)。

While none of this is directly related to Clean Architecture, this is how you can make your component's implementations independent of their dependencies.虽然这些都与 Clean Architecture 没有直接关系,但您可以通过这种方式使组件的实现独立于它们的依赖项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM