我一直在使用两个库,SFML 和 Box2D,同时非常痛苦地确保它们的任何函数或类都没有暴露在我的代码主体中,将它们隐藏在类的后面,这些类只是充当一个我的代码和库本身之间的中介。我的调解员采用以下形式:

    class MyWindow{
    public:
        // could be 10 or so functions like below
        int doSomething(int arg){
           return library_window->doSomething(arg);
        };
    private:
        library::window * library_window;
    };

这样做的好处,至少我被告知,我的主要代码体不依赖于库,如果它发生变化或者我选择使用不同的库,比如 SDL 或 OpenGL SFML 之类的,我可以通过修改中介类来切换。但是必须将接入点编码到我想要使用的每个功能中的痛苦是痛苦和重复的......

这真的是专业程序员应该如何对待外部库吗?值得吗?

我这样做对吗?

最佳答案

您所描述的包装器技术的问题在于您的包装器是透明的(在这个词的真正意义上)——库中的每个方法仍然可以通过包装器对您可见,具有相同的语义、相同的先决条件等. 你可以“看透”你的包装。

只有当你有一天将底层库切换到具有相同语义或至少非常接近相同语义的东西时,像这样的透明包装器才对你有用。考虑这个例子。假设库是 std::fstream,并且您的应用程序需要读取和写入文件,并且假设您勤奋地编写了一个包装器:

class MyFile {
    std::fstream* fst;
public:
    void writeData(void* data, size_t count) {
        fst->write((const char*) data, count);
    }
    void readData(void* buffer, size_t count) {
        fst->read((char*) data, count);
    }
    // etc, etc.
};

现在假设您想要(或需要)切换到具有非阻塞读取和写入的异步 I/O。您的透明包装器根本无法帮助您进行转换。异步读需要两种方法,一种是开始读操作​​,一种是确认读已经完成。它还需要应用程序 promise 不会在这两个方法调用之间使用缓冲区。

总而言之,库接口(interface)包装器只有在非常小心地设计为不透明时才有用(好的接口(interface)是不透明的)。此外,要有用,您包装的库必须是您非常熟悉的东西。因此,boost::filesystem 可以“包装”DOS 和 Unix 的路径名,因为作者非常了解 POSIX、UNIX 和 DOS 路径名,并且正在设计“包装器”以有效地封装这些实现。

根据你的描述,在我看来,你的努力最终会白费。简单总比复杂好,除非包装器真的在封装一些东西(即隐藏底层库),否则直接比间接好。

这不是编写意大利面的许可证——您的应用程序仍然需要主要组件的结构和隔离(例如,将 UI 与应用程序提供的实际计算/模拟/文档隔离)。如果你做得对,有一天交换库将是一项无需任何包装代码的可管理任务。

关于c++ - 应该包装外部图书馆吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7265506/

10-13 08:08