c++ 如何创建一个包含多个类的类工厂,这些类具有不同的参数,但返回类型相同?

mzmfm0qo  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(166)

我在这里问这个问题是想从一个真实的人的Angular 来听。
我想创建一个具有以下签名的类工厂:

Component* (GameObject*, ...)

字符串
在某些情况下,这是我的ProximentFactory类:

.h

#pragma once

// Dependencies | std
#include <functional>
#include <vector>
#include <utility>

// Dependencies | CoreEngine
#include "Component.h"
#include "GameObject.h"

class ComponentFactory {
    // Object
    public:
        // Properties
        std::vector<std::pair<const type_info*, std::function<Component* (GameObject* gameObject)>>> factory = std::vector<std::pair<const type_info*, std::function<Component* (GameObject*)>>>();

        // Constructor / Destructor
        ComponentFactory();
        ~ComponentFactory();

        // Functions
        void addRegistry(const type_info* typeInfo, std::function<Component* (GameObject*)> contructor);
        Component* create(GameObject* gameObject, const type_info* typeInfo);
};

.cpp

#include "ComponentFactory.h"

// class ComponentFactory

// Object | public

// Constructor / Destructor
ComponentFactory::ComponentFactory() {

}
ComponentFactory::~ComponentFactory() {

}

// Functions
void ComponentFactory::addRegistry(const type_info* typeInfo, std::function<Component* (GameObject*)> constructor) {
    std::pair<const type_info*, std::function<Component* (GameObject*)>> registry = std::pair<const type_info*, std::function<Component* (GameObject*)>>(typeInfo, constructor);
    factory.push_back(registry);
}
Component* ComponentFactory::create(GameObject* gameObject, const type_info* typeInfo) {
    for (const std::pair<const type_info*, std::function<Component* (GameObject*)>>& registry : factory)
        if (registry.first == typeInfo)
            return registry.second(gameObject);
    return nullptr;
}


我的代码的问题是,某些组件不仅仅接受GameObject*作为参数。它需要能够返回Component*,第一个参数必须是GameObject*,从那里开始,任何其他参数和任何数量的参数。例如:

Component* (GameObject*, ...)


目标是向组件工厂传递const type_info*GameObject及其参数,并获得Component*指针作为结果。
注意事项:我的组件工厂必须是一个对象,因为我需要不同的组件工厂,并且我试图用更大的代码构建has a关系。
注意:Component是其他类派生的类。
注意:每个Component对象都有一个cont type_info* typeInfo变量,它的子对象也有。
最后,它应该看起来像这样:

componentFactory.create(gameObject, *typeid(someClass), ...)


下面是一个我正在阅读的JSON示例,正如在评论部分中所要求的那样。一旦它被读取,我就会尝试创建其中指定的对象。正如你所看到的,type_info.name()在文件中保存为type。我将其与组件工厂中存储的type_info进行匹配。

{
    "gameObjects": [
        {
            "id": 1,
            "name": "Camera Game Object",
            "transform": {
                "position": [
                    0.0,
                    0.0,
                    0.0
                ],
                "rotation": [
                    0.0,
                    0.0,
                    0.0
                ],
                "scale": [
                    1.0,
                    1.0,
                    1.0
                ]
            }
        }
    ],
    "transformRelationships": null,
    "components": [
        {
            "gameObjectIndex": 0,
            "type": "class Camera2D",
            "data": {
                "graphicsContextIndex": 0,
                "viewSize": 16.0,
                "backgroundColor": [
                    0.15000000596046448,
                    0.15000000596046448,
                    0.15000000596046448,
                    1.0
                ]
            }
        },
        {
            "gameObjectIndex": 0,
            "type": "class CameraController",
            "data": {
                "stength": 1.0
            }
        },
        {
            "gameObjectIndex": 0,
            "type": "class GameObjectController",
            "data": {
                "strenght": 0.10000000149011612
            }
        },
        {
            "gameObjectIndex": 0,
            "type": "class EmptyComponent",
            "data": {}
        }
    ]
}

2mbi3lxu

2mbi3lxu1#

我使用了两个Component,并假设一个类似于下面的实现:

namespace ns { // your namespace

struct Component {
    virtual ~Component() = default;
};

struct Camera2D : Component {
    Camera2D(std::size_t graphicsContextIndex, double viewSize,
             const std::array<double, 4>& backgroundColor) :
        graphicsContextIndex(graphicsContextIndex),
        viewSize(viewSize),
        backgroundColor(backgroundColor)
    {}

    std::size_t graphicsContextIndex;
    double viewSize;
    std::array<double, 4> backgroundColor;
};

struct CameraController : Component {
    CameraController(double strength) : strength(strength) {}

    double strength;
};

字符串
然后一个工厂,下面的componentFactory,可以简单地是一个函数,它有一个从类名到示例化该类的函数的Map。因为你想要Component*,而类可能继承自Component,这个工厂函数返回一个std::unique_ptr<Component>

template<class T>
std::unique_ptr<Component> getComponentPtr(const json& j) {
    // use the nlohmann::adl_serializer:
    return j.get<std::unique_ptr<T>>();
}

std::unique_ptr<Component> componentFactory(const json& j) {
    static const std::unordered_map<std::string_view,
                                    std::unique_ptr<Component>(*)(const json&)>
    functions{
        {"class Camera2D", &getComponentPtr<Camera2D> },
        {"class CameraController", &getComponentPtr<CameraController> },
    };
    const auto& type = j.at("type").get<std::string>(); // class name
    const auto& factfunc = functions.at(type); // get the function
    return factfunc(j); // and call it
}

}  // namespace ns


要做到这一点,你还需要为你的类型添加nlohmann::adl_serializer专门化:

namespace nlohmann {
template <>
struct adl_serializer<std::unique_ptr<ns::Camera2D>> {
    static std::unique_ptr<ns::Camera2D> from_json(const json& j) {
        const auto& data = j.at("data");
        return std::make_unique<ns::Camera2D>(
            data.at("graphicsContextIndex").get<std::size_t>(),
            data.at("viewSize").get<double>(),
            data.at("backgroundColor").get<std::array<double, 4>>()
        );
    }
};

template <>
struct adl_serializer<std::unique_ptr<ns::CameraController>> {
    static std::unique_ptr<ns::CameraController> from_json(const json& j) {
        const auto& data = j.at("data");
        return std::make_unique<ns::CameraController>(
            data.at("strength").get<double>()
        );
    }
};
}  // namespace nlohmann


Demo

相关问题