c++ - 这么复杂的C++类设计的目的是什么?

标签 c++ design-patterns

我看到了一个开源的 C++ 代码,我很好奇,为什么人们要这样设计类?

首先,这里是抽象类:

class BaseMapServer
    {
    public:
        virtual ~BaseMapServer(){}

        virtual void LoadMapInfoFromFile(const std::string &file_name) = 0;
        virtual void LoadMapFromFile(const std::string &map_name) = 0;
        virtual void PublishMap() = 0;
        virtual void SetMap() = 0;
        virtual void ConnectROS() = 0;
    };

这里没有什么特别的,拥有一个抽象类可能有几个很好理解的原因。所以从这一点来看,我想也许作者想要在其他类之间共享共同的特性。所以这是下一个类,它是一个单独的类,但实际上包含一个上面提到的抽象类类型的指针(实际的 cpp 文件,其他两个类是头文件):

class MapFactory
{
    BaseMapServer *CreateMap(
            const std::string &map_type,
            rclcpp::Node::SharedPtr node, const std::string &file_name)
        {
            if (map_type == "occupancy") return new OccGridServer(node, file_name);
            else
            {
                RCLCPP_ERROR(node->get_logger(), "map_factory.cpp 15: Cannot load map %s of type %s", file_name.c_str(), map_type.c_str());
                throw std::runtime_error("Map type not supported")
            }
        }
};

现在有趣的事情来了,这是抽象类的子类:

class OccGridServer : public BaseMapServer
    {
    public:
        explicit OccGridServer(rclcpp::Node::SharedPtr node) : node_(node) {}
        OccGridServer(rclcpp::Node::SharedPtr node, std::string file_name);
        OccGridServer(){}
        ~OccGridServer(){}

        virtual void LoadMapInfoFromFile(const std::string &file_name);
        virtual void LoadMapFromFile(const std::string &map_name);
        virtual void PublishMap();
        virtual void SetMap();
        virtual void ConnectROS();

    protected:
        enum MapMode { TRINARY, SCALE, RAW };

        // Info got from the YAML file
        double origin_[3];
        int negate_;
        double occ_th_;
        double free_th_;
        double res_;
        MapMode mode_ = TRINARY;
        std::string frame_id_ = "map";
        std::string map_name_;

        // In order to do ROS2 stuff like creating a service we need a node:
        rclcpp::Node::SharedPtr node_;

        // A service to provide the occupancy grid map and the message with response:
        rclcpp::Service<nav_msgs::srv::GetMap>::SharedPtr occ_service_;
        nav_msgs::msg::OccupancyGrid map_msg_;

        // Publish map periodically for the ROS1 via bridge:
        rclcpp::TimerBase::SharedPtr timer_;
    };

那么 MapFactory 类的目的是什么?

更具体地说——创建一个包含抽象类BaseMapServer指针的类有什么好处,它是一个构造函数(我相信),这个奇怪的构造函数为新的创建了一个内存名为 OccGridServer 的对象并返回它?我只写了这个就很困惑。我真的很想成为一名更好的 C++ 编码员,我非常想知道这些代码设计背后的 secret 。

最佳答案

MapFactory 类用于根据传递给它的参数创建 BaseMapServer 的正确子类实例。

在这种特殊情况下,只有一个子类实例,但也许有计划添加更多。然后当添加更多时,工厂方法看起来像这样:

BaseMapServer *CreateMap(
        const std::string &map_type,
        rclcpp::Node::SharedPtr node, const std::string &file_name)
    {
        if (map_type == "occupancy") return new OccGridServer(node, file_name);
        // create Type2Server
        else if (map_type == "type2") return new Type2Server(node, file_name);   
        // create Type3Server
        else if (map_type == "type3") return new Type3Server(node, file_name);
        else
        {
            RCLCPP_ERROR(node->get_logger(), 
                         "map_factory.cpp 15: Cannot load map %s of type %s", 
                         file_name.c_str(), map_type.c_str());
            throw std::runtime_error("Map type not supported")
        }
    }

这样做的好处是调用者不需要知道正在使用的确切子类,事实上,底层子类可能会在后台发生变化甚至被替换,而无需修改调用代码。工厂方法为您内化了这个逻辑。

关于c++ - 这么复杂的C++类设计的目的是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53413869/

相关文章:

c# - 我如何在类型安全的枚举模式上使用 switch 语句

c++ - 从 constexpr 函数返回一个类需要使用 g++ 的 virtual 关键字

c++以编程方式确定成员的内存布局

c++ - 二叉搜索树 C++(父级)

c# - 隐藏/显示表单元素的设计模式

java - Null Object Pattern是否占用内存

c++ - Qt 5 在用户输入时播放 wav 声音

c++ - 迭代器在 C++ 中的工作原理

design-patterns - 使用哈希函数进行文件存储?

javascript - 仅设置一次模块属性