c++ - 进行如此复杂的 C++ 类设计的目的是什么?
问题描述
我遇到了一个开源 C++ 代码,我很好奇,为什么人们会这样设计这些类?
所以首先,这是 Abstract 类:
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++ 编码器,我迫切地想知道这些代码设计背后的秘密。
解决方案
该类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")
}
}
这样做的好处是调用者不需要知道正在使用的确切子类,实际上底层子类可能会在底层更改甚至被替换,而无需修改调用代码。工厂方法为您内化了这个逻辑。
推荐阅读
- python-3.x - 在文件夹中选择具有其名称的特定文件,然后对其进行操作(Python)
- c - 如何使用 C 套接字从网络服务器下载二进制文件(在本例中为图像)?
- python - Python - ImportError:DLL加载失败:在VSCode中找不到指定的模块,但在Spyder中可以找到
- apl - 根据值从矩阵中进行选择的惯用方法
- php - 使用 Guzzle/Goutte(PHP,调试)导航表单并从网站抓取 DOM 元素
- c++17 - 为什么 std::string_view 不是微不足道的?
- java - 每当我单击按钮时,Android 应用程序就会关闭
- php - 在 ajax 响应期间出现 500 内部问题
- sql - 具有计数的 SQL Server 函数无法按预期工作
- r - 如何检查列值是否是 R 中同一 tibble 的另一个列表类型列的成员?