如何创建包装器或中间层来访问 class,而不公开它?

How to create a wrapper or intermediate layer to access a class, without exposing it?

我使用第三方引擎,它有一个 class“Sprite”。我的 classes 使用 sprite,并调用它的方法。

“雪碧”将来有可能被其他游戏引擎取代。我想在我的 class 和 Sprite 之间有一个层,这样以后就可以很容易地换掉 Sprite。

我认为至少有两种方法可以做到这一点:

  1. 实现一个包装器 class,它对 sprite 中的每个方法都有一个桥接方法,我的代码使用它来访问 sprite。

例如:

Wrapper{
private:
Sprite* foo;
public:

  void method1(){
     foo->method1();
   }

   int method2(){
      return foo->method2();
    }
}

这种方法的缺点是在 Sprite 中为每个方法编写一个方法需要做很多工作,即使它所做的只是调用方法并返回任何结果。每次sprite的变化也是很多维护工作。

  1. 备选方案 2:通过重载 -> 运算符实现某种魔法。

     struct LoggingFoo : public Sprite {
     void log() const { } //Just a method for logging.Doesn't matter. 
    
    
     Foo const *operator -> () const { log(); return this; }
     Foo       *operator -> ()       { log(); return this; }
    

    };

不太确定使用此选项时要记住的所有事项?例如,class 方法会怎样?对于这个用例 public 仅继承 Sprite 有意义吗?

注意:在实践中,我的代码中没有打算从 Sprite 继承的对象。

编辑: 创建包装器但公开所有 public 成员变量和函数的最简洁方法是什么?例如,不必指定要公开的每个变量和函数 ?

您还可以考虑使用私有(即根据)继承对包装器进行稍微不同的实现。

此实现消除了包装每个函数的负担,而只是为每个要公开的函数添加一个 using 语句。

#include <iostream>

class Sprite
{
public:
    Sprite() : d_value(0) {}
    
    void method1() { std::cout << "Sprite::method1()\n"; }
    void method2() { std::cout << "Sprite::method2()\n"; }
    
    int d_value;
};

class Wrapper : private Sprite
{
public:
    using Sprite::method1;
    using Sprite::method2;
    using Sprite::d_value;
};

int main()
{
    Wrapper w;
    w.method1();
    w.method2();
    w.d_value = 3;

    return 0;
}

Live Example

您只需要创建一个公开继承自 Sprite 的 Wrapper class 并使用它。自动完全继承Wrapperclass中Spriteclass的所有方法和变量,可见度相同:

class Sprite
{
    public:
        void foo(){};
        void bar(){};
        
        int mode = 0;
};

class Wrapper : public Sprite
{
};

int main()
{
    Wrapper w;
    w.foo();
    w.mode = 5;
    w.bar();
}

如果您将来切换到另一个库,您将从新的 class 继承 Wrapper 并仅实现已删除或更改的方法:

class NewSprite
{
    public:
        void foo(){}; // same interface
        void new_bar(int mode){};
};

class Wrapper : public NewSprite
{
    public:
        void bar() // wrap new method
        {
            new_bar(mode);
        }
        
        int mode = 0;
};

但更好的方法是构建一个 higher-level 包装器接口,这样当您完全更改库 API 时,您不必重写每个方法:

class Wrapper
{
    public:
        void do_operation() // high-level interface
        {
            s_.foo();
            s_.mode = 5;
            s_.bar();
        }
        
    protected:
        Sprite s_;
};

class Wrapper
{
    public:
        void do_operation() // high-level interface
        {
            s_.foo();
            mode = 5;
            s_.new_bar(mode);
        }
        
        int mode = 0;
        
    protected:
        NewSprite s_;
};

int main()
{
    Wrapper w;
    w.do_operation();
}