如何创建包装器或中间层来访问 class,而不公开它?
How to create a wrapper or intermediate layer to access a class, without exposing it?
我使用第三方引擎,它有一个 class“Sprite”。我的 classes 使用 sprite,并调用它的方法。
“雪碧”将来有可能被其他游戏引擎取代。我想在我的 class 和 Sprite 之间有一个层,这样以后就可以很容易地换掉 Sprite。
我认为至少有两种方法可以做到这一点:
- 实现一个包装器 class,它对 sprite 中的每个方法都有一个桥接方法,我的代码使用它来访问 sprite。
例如:
Wrapper{
private:
Sprite* foo;
public:
void method1(){
foo->method1();
}
int method2(){
return foo->method2();
}
}
这种方法的缺点是在 Sprite 中为每个方法编写一个方法需要做很多工作,即使它所做的只是调用方法并返回任何结果。每次sprite的变化也是很多维护工作。
备选方案 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;
}
您只需要创建一个公开继承自 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();
}
我使用第三方引擎,它有一个 class“Sprite”。我的 classes 使用 sprite,并调用它的方法。
“雪碧”将来有可能被其他游戏引擎取代。我想在我的 class 和 Sprite 之间有一个层,这样以后就可以很容易地换掉 Sprite。
我认为至少有两种方法可以做到这一点:
- 实现一个包装器 class,它对 sprite 中的每个方法都有一个桥接方法,我的代码使用它来访问 sprite。
例如:
Wrapper{
private:
Sprite* foo;
public:
void method1(){
foo->method1();
}
int method2(){
return foo->method2();
}
}
这种方法的缺点是在 Sprite 中为每个方法编写一个方法需要做很多工作,即使它所做的只是调用方法并返回任何结果。每次sprite的变化也是很多维护工作。
备选方案 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;
}
您只需要创建一个公开继承自 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();
}