假设您在 2D 游戏框架或类似的东西(例如 GUI 框架)中有实体,其中有各种类型的实体共享位置和旋转等公共属性,但其中一些属性必须在每个实体类型上处理例如,旋转一个简单的精灵与旋转一个绑定的 2D 动画骨架不同。
显然,这可以通过传统的 OOP 继承层次结构来处理......但是,我感兴趣的是使用“组合而不是继承”来表示这些实体,方法是拥有一个没有任何东西继承自被调用的具体类,该类actor
具有用于状态的香草成员变量跨实体类型以相同的方式处理,但也与包含必须以每个实体类型方式处理的状态的变体具有 has-a 关系。
该设计可以按如下方式工作:
#include <iostream>
#include <variant>
struct actor_state_1 {
float rotation_;
//point position;
// etc...
void set_rotation(float theta) {
rotation_ = theta;
// say there are different things that need to happen here
// for different actor types...
// e.g. if this is an animation skeleton you need to find the
// the root bone and rotate that, etc.
std::cout << "actor_state_1 set_rotation\n";
}
void set_position(const std::tuple<float, float>& pos) {
// etc ...
}
float get_rotation() const {
return rotation_;
}
// get_position, etc...
};
struct actor_state_2 {
float rotation_;
void set_rotation(float theta) {
rotation_ = theta;
std::cout << "actor_state_2 set_rotation\n";
}
void set_position(const std::tuple<float, float>& pos) {
// etc ...
}
float get_rotation() const {
return rotation_;
}
// get_position, etc...
};
using state_variant = std::variant<actor_state_1, actor_state_2>;
class actor {
private:
state_variant state_;
// common properties...
float alpha_transparency; // etc.
public:
actor(const actor_state_1& state) :
state_(state)
{}
actor(const actor_state_2& state) :
state_(state)
{}
void rotate_by(float theta) {
auto current_rotation = get_rotation();
std::visit(
[current_rotation, theta](auto& a) { a.set_rotation(current_rotation + theta); },
state_
);
}
float get_rotation() const {
return std::visit(
[](const auto& a) {return a.get_rotation(); },
state_
);
}
void move_by(const std::tuple<float, float>& translation_vec);
std::tuple<float, float> get_postion() const; // etc.
};
int main() {
auto a = actor(actor_state_2{ 90.0f });
a.rotate_by(45.0f);
std::cout << a.get_rotation() << "\n";
}
然而,我觉得每个属性的冗长程度和重复样板代码的数量使这样的设计变得笨拙。但是,我想不出一种通过使用模板来减少样板文件的方法。似乎应该有一种方法至少可以为actor::get_rotation()
上面的“直通吸气剂”制作模板,但我不知道一种对成员函数进行参数化的方法,这似乎是你需要做的.
有没有人对像这样不那么冗长或使用更少样板的设计有想法?