samedi 5 décembre 2015

Menu data structure and interface design

I am trying to develop a generic, flexible and modular data structure to represent a menu. I understand the OOP concepts but I'm a bit inexperienced, so I wanted to share my design ideas with the experts. Also note that this implementation can't use the STL.

The way I see this in my head is:

  • class MenuItem: it is a navigational node, i.e. it just contains other nodes, a string, and no modifiable parameter (which is the main purpose of this menu - modifying categorized parameters)
  • class MenuItemUINT16Input: I call this an end point node, since it has a modifiable parameter, and therefore no more child nodes. It is derived from the MenuItem class. The UINT16 sufix represents the type of the contained parameter type. I have not been able to find any other way to further generalize this MenuItemInput component to accept other data types (float, bool, char[], ...) by deriving from it, or being derived itself from an additional interface. See the code for clarification.
  • class MenuController: this one manages the MenuItems, keeping a reference to the current item and providing a public interface to navigate the menu. It also needs to have a mechanism to provide the required information for the object (not shown here) that prints the menu.

Header file:

class MenuItem
{
protected:
  MenuItem* m_pSibling, *m_pChild;
  char m_sInfo[MENU_INFO_STRING_MAX_LEN];
  bool m_active;

  /* --- Option 1 ---    
protected:
  MenuItem* getSibling();
  MenuItem* getChild();
  void setActiveState(bool state);

  friend class MenuController;
     --- Option 1 --- */

public:
  MenuItem(MenuItem* pSibling, MenuItem* pChild, bool active, const char* sInfo);
  virtual ~MenuItem();
  bool isActive();
  const char* getInfoString();
  virtual bool isEndPoint();    
};

// --- Option 2 ---
class MenuItemForMenuController : public MenuItem
{
public:
  MenuItem* getSibling();
  MenuItem* getChild();
  void setActiveState(bool state);
  MenuItemForMenuController(MenuItem* pSibling, MenuItem* pChild, bool active, const char* sInfo);
  ~MenuItemForMenuController();
};
// --- Option 2 ---

class MenuItemUINT16Input : public MenuItem
{
protected:
  uint16_t& m_pCurrentValue;

  /* --- Option 1 ---
protected:
  void setCurrentValue(uint16_t value);

  friend class MenuController;
     --- Option 1 --- */

public:
  MenuItemUINT16Input(MenuItem* pSibling, bool active, uint16_t& pCurrentValue, const char* sInfo);
  virtual ~MenuItemUINT16Input();
  uint16_t getCurrentValue();
  virtual bool isEndPoint();
};

// --- Option 2 ---
class MenuItemUINT16InputForMenuController : public MenuItemUINT16Input
{
  // as before
};

Now, I would like to have a public interface providing "read-only" access to MenuItem objects, to ensure that the printing object they are passed to cannot modify them. However, I need an interface with greater control for the MenuController, although ideally not full control.

I can think of two way to make this:

  • Option 1: use friend class MenuController, thus giving full access to MenuItem objects, and by my own convention, using only the functions defined in the access level where the friend class has been declared. Then there would still be some degree of encapsulation.
  • Option 2: subclassing all MenuItem, MenuItemUINT16INPUT, and others that will be added in the future with additional public functions to be used by MenuController.

I'm concerned with the efficiency in terms of speed and memory overhead. I'd like to know if there is a better/another way to do this. I'd like to know as well if there might be another solution to generalize the data type contained in the item objects.

Thanks in advance.

Aucun commentaire:

Enregistrer un commentaire