What is the purpose of having such complicated C++ class design?












11














I came across an open source C++ code and I got curious, why do people design the classes this way?



So first things first, here is the Abstract class:



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;
};


Nothing special here and having an abstract class can have several well understood reasons. So from this point, I thought maybe author wanted to share common features among other classes. So here is the next class, which is a seperate class but actually holds a pointer of type abstract class mentioned above (actual cpp file, other two classes are header files) :



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")
}
}
};


And now the interesting thing comes, here is the child class of the abstract class:



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_;
};


So what is the purpose of the MapFactory class?



To be more specific - what is the advantage of creating a class which holds a pointer of type Abstract class BaseMapServer which is a constructor (I believe) and this weird constructor creates a memory for the new object called OccGridServer and returns it? I got so confused by only writing this. I really want to become a better C++ coder and I am desperate to know the secret behind these code designs.










share|improve this question




















  • 6




    You're faced with a design pattern, called "factory".
    – Dominique
    Nov 21 '18 at 14:09






  • 2




    See en.wikipedia.org/wiki/Factory_method_pattern
    – MrTux
    Nov 21 '18 at 14:09










  • You're really asking about what problem the Factory pattern solves. It's simple if you know how to look at it: The code calling MapFactory::CreateMap needs to know BaseMapServer and the string "occupancy", but it does not have to know OccGridServer to create one.
    – Quentin
    Nov 21 '18 at 14:10










  • Inside MapFactory, CreateMap is a member function which returns a pointer to a BaseFactory. It is not a constructor.
    – 0x499602D2
    Nov 21 '18 at 14:10










  • It's a way of creating an object without knowing its exact type.
    – Tim Randall
    Nov 21 '18 at 14:10
















11














I came across an open source C++ code and I got curious, why do people design the classes this way?



So first things first, here is the Abstract class:



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;
};


Nothing special here and having an abstract class can have several well understood reasons. So from this point, I thought maybe author wanted to share common features among other classes. So here is the next class, which is a seperate class but actually holds a pointer of type abstract class mentioned above (actual cpp file, other two classes are header files) :



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")
}
}
};


And now the interesting thing comes, here is the child class of the abstract class:



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_;
};


So what is the purpose of the MapFactory class?



To be more specific - what is the advantage of creating a class which holds a pointer of type Abstract class BaseMapServer which is a constructor (I believe) and this weird constructor creates a memory for the new object called OccGridServer and returns it? I got so confused by only writing this. I really want to become a better C++ coder and I am desperate to know the secret behind these code designs.










share|improve this question




















  • 6




    You're faced with a design pattern, called "factory".
    – Dominique
    Nov 21 '18 at 14:09






  • 2




    See en.wikipedia.org/wiki/Factory_method_pattern
    – MrTux
    Nov 21 '18 at 14:09










  • You're really asking about what problem the Factory pattern solves. It's simple if you know how to look at it: The code calling MapFactory::CreateMap needs to know BaseMapServer and the string "occupancy", but it does not have to know OccGridServer to create one.
    – Quentin
    Nov 21 '18 at 14:10










  • Inside MapFactory, CreateMap is a member function which returns a pointer to a BaseFactory. It is not a constructor.
    – 0x499602D2
    Nov 21 '18 at 14:10










  • It's a way of creating an object without knowing its exact type.
    – Tim Randall
    Nov 21 '18 at 14:10














11












11








11


1





I came across an open source C++ code and I got curious, why do people design the classes this way?



So first things first, here is the Abstract class:



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;
};


Nothing special here and having an abstract class can have several well understood reasons. So from this point, I thought maybe author wanted to share common features among other classes. So here is the next class, which is a seperate class but actually holds a pointer of type abstract class mentioned above (actual cpp file, other two classes are header files) :



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")
}
}
};


And now the interesting thing comes, here is the child class of the abstract class:



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_;
};


So what is the purpose of the MapFactory class?



To be more specific - what is the advantage of creating a class which holds a pointer of type Abstract class BaseMapServer which is a constructor (I believe) and this weird constructor creates a memory for the new object called OccGridServer and returns it? I got so confused by only writing this. I really want to become a better C++ coder and I am desperate to know the secret behind these code designs.










share|improve this question















I came across an open source C++ code and I got curious, why do people design the classes this way?



So first things first, here is the Abstract class:



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;
};


Nothing special here and having an abstract class can have several well understood reasons. So from this point, I thought maybe author wanted to share common features among other classes. So here is the next class, which is a seperate class but actually holds a pointer of type abstract class mentioned above (actual cpp file, other two classes are header files) :



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")
}
}
};


And now the interesting thing comes, here is the child class of the abstract class:



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_;
};


So what is the purpose of the MapFactory class?



To be more specific - what is the advantage of creating a class which holds a pointer of type Abstract class BaseMapServer which is a constructor (I believe) and this weird constructor creates a memory for the new object called OccGridServer and returns it? I got so confused by only writing this. I really want to become a better C++ coder and I am desperate to know the secret behind these code designs.







c++ design-patterns






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 21 '18 at 17:36









mrflash818

6621018




6621018










asked Nov 21 '18 at 14:06









Edmund

829




829








  • 6




    You're faced with a design pattern, called "factory".
    – Dominique
    Nov 21 '18 at 14:09






  • 2




    See en.wikipedia.org/wiki/Factory_method_pattern
    – MrTux
    Nov 21 '18 at 14:09










  • You're really asking about what problem the Factory pattern solves. It's simple if you know how to look at it: The code calling MapFactory::CreateMap needs to know BaseMapServer and the string "occupancy", but it does not have to know OccGridServer to create one.
    – Quentin
    Nov 21 '18 at 14:10










  • Inside MapFactory, CreateMap is a member function which returns a pointer to a BaseFactory. It is not a constructor.
    – 0x499602D2
    Nov 21 '18 at 14:10










  • It's a way of creating an object without knowing its exact type.
    – Tim Randall
    Nov 21 '18 at 14:10














  • 6




    You're faced with a design pattern, called "factory".
    – Dominique
    Nov 21 '18 at 14:09






  • 2




    See en.wikipedia.org/wiki/Factory_method_pattern
    – MrTux
    Nov 21 '18 at 14:09










  • You're really asking about what problem the Factory pattern solves. It's simple if you know how to look at it: The code calling MapFactory::CreateMap needs to know BaseMapServer and the string "occupancy", but it does not have to know OccGridServer to create one.
    – Quentin
    Nov 21 '18 at 14:10










  • Inside MapFactory, CreateMap is a member function which returns a pointer to a BaseFactory. It is not a constructor.
    – 0x499602D2
    Nov 21 '18 at 14:10










  • It's a way of creating an object without knowing its exact type.
    – Tim Randall
    Nov 21 '18 at 14:10








6




6




You're faced with a design pattern, called "factory".
– Dominique
Nov 21 '18 at 14:09




You're faced with a design pattern, called "factory".
– Dominique
Nov 21 '18 at 14:09




2




2




See en.wikipedia.org/wiki/Factory_method_pattern
– MrTux
Nov 21 '18 at 14:09




See en.wikipedia.org/wiki/Factory_method_pattern
– MrTux
Nov 21 '18 at 14:09












You're really asking about what problem the Factory pattern solves. It's simple if you know how to look at it: The code calling MapFactory::CreateMap needs to know BaseMapServer and the string "occupancy", but it does not have to know OccGridServer to create one.
– Quentin
Nov 21 '18 at 14:10




You're really asking about what problem the Factory pattern solves. It's simple if you know how to look at it: The code calling MapFactory::CreateMap needs to know BaseMapServer and the string "occupancy", but it does not have to know OccGridServer to create one.
– Quentin
Nov 21 '18 at 14:10












Inside MapFactory, CreateMap is a member function which returns a pointer to a BaseFactory. It is not a constructor.
– 0x499602D2
Nov 21 '18 at 14:10




Inside MapFactory, CreateMap is a member function which returns a pointer to a BaseFactory. It is not a constructor.
– 0x499602D2
Nov 21 '18 at 14:10












It's a way of creating an object without knowing its exact type.
– Tim Randall
Nov 21 '18 at 14:10




It's a way of creating an object without knowing its exact type.
– Tim Randall
Nov 21 '18 at 14:10












3 Answers
3






active

oldest

votes


















5














The MapFactory class is used to create the correct subclass instance of BaseMapServer based on the parameters passed to it.



In this particular case there is only one child class instance, but perhaps there are plans to add more. Then when more are added the factory method can look something like this:



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")
}
}


This has the advantage that the caller doesn't need to know the exact subclass being used, and in fact the underlying subclass could potentially change or even be replaced under the hood without the calling code needing to be modified. The factory method internalizes this logic for you.






share|improve this answer



















  • 1




    Ok I see, that is super clever and your way of explaining with the example actually helped me to understand better than reading on Wikipedia.
    – Edmund
    Nov 21 '18 at 14:14










  • Imagine the code is in a shared library used by thousands of applications and a bug is found in it. Imagine further that fixing the bug requires adding a new data member to OccGridServer. This pattern means those thousands of applications don't have to be recompiled and redeployed, only the library does.
    – David Schwartz
    Nov 21 '18 at 17:46



















0














Its a Factory pattern. See https://en.wikipedia.org/wiki/Factory_method_pattern. It looks like the current code only supports one implementation (OccGridServer), but more could be added at a future date. Conversely, if there's only ever likely to be one concrete implementation, then it's overdesign.






share|improve this answer





























    0














    This is example of the factory design pattern. The use case is this: there are several types of very similar classes that will be used in code. In this case, OccGridServer is the only one actually shown, but a generic explanation might reference hypothetical Dog, Cat, Otter, etc. classes. Because of their similarity, some polymorphism is desired: if they all inherit from a base class Animal they can share virtual class methods like ::genus, ::species, etc., and the derived classes can be pointed to or referred to with base class pointers/references. In your case, OccGridServer inherits from BaseMapServer; presumably there are other derived classes as well, and pointers/references.



    If you know which derived class is needed at compile time, you would normally just call its constructor. The point of the factory design pattern is to simplify selection of a derived class when the particular derived class is not known until runtime. Imagine that a user picks their favorite animal by selecting a button or typing in a name. This generally means that somewhere there's a big if/else block that maps from some type of I/O disambiguator (string, enum, etc.) to a particular derived class type, calling its constructor. It's useful to encapsulate this in a factory pattern, which can act like a named constructor that takes this disambiguator as a "constructor" parameter and finds the correct derived class to construct.



    Typically, by the way, CreateMap would be a static method of BaseMapServer. I don't see why a separate class for the factory function is needed in this case.






    share|improve this answer





















      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53413869%2fwhat-is-the-purpose-of-having-such-complicated-c-class-design%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      5














      The MapFactory class is used to create the correct subclass instance of BaseMapServer based on the parameters passed to it.



      In this particular case there is only one child class instance, but perhaps there are plans to add more. Then when more are added the factory method can look something like this:



      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")
      }
      }


      This has the advantage that the caller doesn't need to know the exact subclass being used, and in fact the underlying subclass could potentially change or even be replaced under the hood without the calling code needing to be modified. The factory method internalizes this logic for you.






      share|improve this answer



















      • 1




        Ok I see, that is super clever and your way of explaining with the example actually helped me to understand better than reading on Wikipedia.
        – Edmund
        Nov 21 '18 at 14:14










      • Imagine the code is in a shared library used by thousands of applications and a bug is found in it. Imagine further that fixing the bug requires adding a new data member to OccGridServer. This pattern means those thousands of applications don't have to be recompiled and redeployed, only the library does.
        – David Schwartz
        Nov 21 '18 at 17:46
















      5














      The MapFactory class is used to create the correct subclass instance of BaseMapServer based on the parameters passed to it.



      In this particular case there is only one child class instance, but perhaps there are plans to add more. Then when more are added the factory method can look something like this:



      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")
      }
      }


      This has the advantage that the caller doesn't need to know the exact subclass being used, and in fact the underlying subclass could potentially change or even be replaced under the hood without the calling code needing to be modified. The factory method internalizes this logic for you.






      share|improve this answer



















      • 1




        Ok I see, that is super clever and your way of explaining with the example actually helped me to understand better than reading on Wikipedia.
        – Edmund
        Nov 21 '18 at 14:14










      • Imagine the code is in a shared library used by thousands of applications and a bug is found in it. Imagine further that fixing the bug requires adding a new data member to OccGridServer. This pattern means those thousands of applications don't have to be recompiled and redeployed, only the library does.
        – David Schwartz
        Nov 21 '18 at 17:46














      5












      5








      5






      The MapFactory class is used to create the correct subclass instance of BaseMapServer based on the parameters passed to it.



      In this particular case there is only one child class instance, but perhaps there are plans to add more. Then when more are added the factory method can look something like this:



      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")
      }
      }


      This has the advantage that the caller doesn't need to know the exact subclass being used, and in fact the underlying subclass could potentially change or even be replaced under the hood without the calling code needing to be modified. The factory method internalizes this logic for you.






      share|improve this answer














      The MapFactory class is used to create the correct subclass instance of BaseMapServer based on the parameters passed to it.



      In this particular case there is only one child class instance, but perhaps there are plans to add more. Then when more are added the factory method can look something like this:



      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")
      }
      }


      This has the advantage that the caller doesn't need to know the exact subclass being used, and in fact the underlying subclass could potentially change or even be replaced under the hood without the calling code needing to be modified. The factory method internalizes this logic for you.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Nov 21 '18 at 16:49

























      answered Nov 21 '18 at 14:12









      dbush

      92.9k12101133




      92.9k12101133








      • 1




        Ok I see, that is super clever and your way of explaining with the example actually helped me to understand better than reading on Wikipedia.
        – Edmund
        Nov 21 '18 at 14:14










      • Imagine the code is in a shared library used by thousands of applications and a bug is found in it. Imagine further that fixing the bug requires adding a new data member to OccGridServer. This pattern means those thousands of applications don't have to be recompiled and redeployed, only the library does.
        – David Schwartz
        Nov 21 '18 at 17:46














      • 1




        Ok I see, that is super clever and your way of explaining with the example actually helped me to understand better than reading on Wikipedia.
        – Edmund
        Nov 21 '18 at 14:14










      • Imagine the code is in a shared library used by thousands of applications and a bug is found in it. Imagine further that fixing the bug requires adding a new data member to OccGridServer. This pattern means those thousands of applications don't have to be recompiled and redeployed, only the library does.
        – David Schwartz
        Nov 21 '18 at 17:46








      1




      1




      Ok I see, that is super clever and your way of explaining with the example actually helped me to understand better than reading on Wikipedia.
      – Edmund
      Nov 21 '18 at 14:14




      Ok I see, that is super clever and your way of explaining with the example actually helped me to understand better than reading on Wikipedia.
      – Edmund
      Nov 21 '18 at 14:14












      Imagine the code is in a shared library used by thousands of applications and a bug is found in it. Imagine further that fixing the bug requires adding a new data member to OccGridServer. This pattern means those thousands of applications don't have to be recompiled and redeployed, only the library does.
      – David Schwartz
      Nov 21 '18 at 17:46




      Imagine the code is in a shared library used by thousands of applications and a bug is found in it. Imagine further that fixing the bug requires adding a new data member to OccGridServer. This pattern means those thousands of applications don't have to be recompiled and redeployed, only the library does.
      – David Schwartz
      Nov 21 '18 at 17:46













      0














      Its a Factory pattern. See https://en.wikipedia.org/wiki/Factory_method_pattern. It looks like the current code only supports one implementation (OccGridServer), but more could be added at a future date. Conversely, if there's only ever likely to be one concrete implementation, then it's overdesign.






      share|improve this answer


























        0














        Its a Factory pattern. See https://en.wikipedia.org/wiki/Factory_method_pattern. It looks like the current code only supports one implementation (OccGridServer), but more could be added at a future date. Conversely, if there's only ever likely to be one concrete implementation, then it's overdesign.






        share|improve this answer
























          0












          0








          0






          Its a Factory pattern. See https://en.wikipedia.org/wiki/Factory_method_pattern. It looks like the current code only supports one implementation (OccGridServer), but more could be added at a future date. Conversely, if there's only ever likely to be one concrete implementation, then it's overdesign.






          share|improve this answer












          Its a Factory pattern. See https://en.wikipedia.org/wiki/Factory_method_pattern. It looks like the current code only supports one implementation (OccGridServer), but more could be added at a future date. Conversely, if there's only ever likely to be one concrete implementation, then it's overdesign.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 21 '18 at 14:10









          virgesmith

          36519




          36519























              0














              This is example of the factory design pattern. The use case is this: there are several types of very similar classes that will be used in code. In this case, OccGridServer is the only one actually shown, but a generic explanation might reference hypothetical Dog, Cat, Otter, etc. classes. Because of their similarity, some polymorphism is desired: if they all inherit from a base class Animal they can share virtual class methods like ::genus, ::species, etc., and the derived classes can be pointed to or referred to with base class pointers/references. In your case, OccGridServer inherits from BaseMapServer; presumably there are other derived classes as well, and pointers/references.



              If you know which derived class is needed at compile time, you would normally just call its constructor. The point of the factory design pattern is to simplify selection of a derived class when the particular derived class is not known until runtime. Imagine that a user picks their favorite animal by selecting a button or typing in a name. This generally means that somewhere there's a big if/else block that maps from some type of I/O disambiguator (string, enum, etc.) to a particular derived class type, calling its constructor. It's useful to encapsulate this in a factory pattern, which can act like a named constructor that takes this disambiguator as a "constructor" parameter and finds the correct derived class to construct.



              Typically, by the way, CreateMap would be a static method of BaseMapServer. I don't see why a separate class for the factory function is needed in this case.






              share|improve this answer


























                0














                This is example of the factory design pattern. The use case is this: there are several types of very similar classes that will be used in code. In this case, OccGridServer is the only one actually shown, but a generic explanation might reference hypothetical Dog, Cat, Otter, etc. classes. Because of their similarity, some polymorphism is desired: if they all inherit from a base class Animal they can share virtual class methods like ::genus, ::species, etc., and the derived classes can be pointed to or referred to with base class pointers/references. In your case, OccGridServer inherits from BaseMapServer; presumably there are other derived classes as well, and pointers/references.



                If you know which derived class is needed at compile time, you would normally just call its constructor. The point of the factory design pattern is to simplify selection of a derived class when the particular derived class is not known until runtime. Imagine that a user picks their favorite animal by selecting a button or typing in a name. This generally means that somewhere there's a big if/else block that maps from some type of I/O disambiguator (string, enum, etc.) to a particular derived class type, calling its constructor. It's useful to encapsulate this in a factory pattern, which can act like a named constructor that takes this disambiguator as a "constructor" parameter and finds the correct derived class to construct.



                Typically, by the way, CreateMap would be a static method of BaseMapServer. I don't see why a separate class for the factory function is needed in this case.






                share|improve this answer
























                  0












                  0








                  0






                  This is example of the factory design pattern. The use case is this: there are several types of very similar classes that will be used in code. In this case, OccGridServer is the only one actually shown, but a generic explanation might reference hypothetical Dog, Cat, Otter, etc. classes. Because of their similarity, some polymorphism is desired: if they all inherit from a base class Animal they can share virtual class methods like ::genus, ::species, etc., and the derived classes can be pointed to or referred to with base class pointers/references. In your case, OccGridServer inherits from BaseMapServer; presumably there are other derived classes as well, and pointers/references.



                  If you know which derived class is needed at compile time, you would normally just call its constructor. The point of the factory design pattern is to simplify selection of a derived class when the particular derived class is not known until runtime. Imagine that a user picks their favorite animal by selecting a button or typing in a name. This generally means that somewhere there's a big if/else block that maps from some type of I/O disambiguator (string, enum, etc.) to a particular derived class type, calling its constructor. It's useful to encapsulate this in a factory pattern, which can act like a named constructor that takes this disambiguator as a "constructor" parameter and finds the correct derived class to construct.



                  Typically, by the way, CreateMap would be a static method of BaseMapServer. I don't see why a separate class for the factory function is needed in this case.






                  share|improve this answer












                  This is example of the factory design pattern. The use case is this: there are several types of very similar classes that will be used in code. In this case, OccGridServer is the only one actually shown, but a generic explanation might reference hypothetical Dog, Cat, Otter, etc. classes. Because of their similarity, some polymorphism is desired: if they all inherit from a base class Animal they can share virtual class methods like ::genus, ::species, etc., and the derived classes can be pointed to or referred to with base class pointers/references. In your case, OccGridServer inherits from BaseMapServer; presumably there are other derived classes as well, and pointers/references.



                  If you know which derived class is needed at compile time, you would normally just call its constructor. The point of the factory design pattern is to simplify selection of a derived class when the particular derived class is not known until runtime. Imagine that a user picks their favorite animal by selecting a button or typing in a name. This generally means that somewhere there's a big if/else block that maps from some type of I/O disambiguator (string, enum, etc.) to a particular derived class type, calling its constructor. It's useful to encapsulate this in a factory pattern, which can act like a named constructor that takes this disambiguator as a "constructor" parameter and finds the correct derived class to construct.



                  Typically, by the way, CreateMap would be a static method of BaseMapServer. I don't see why a separate class for the factory function is needed in this case.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 21 '18 at 14:20









                  jwimberley

                  1,137518




                  1,137518






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.





                      Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                      Please pay close attention to the following guidance:


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53413869%2fwhat-is-the-purpose-of-having-such-complicated-c-class-design%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      404 Error Contact Form 7 ajax form submitting

                      How to know if a Active Directory user can login interactively

                      Refactoring coordinates for Minecraft Pi buildings written in Python