Accessing functions and var from all classes, extern? singleton? ino vs main?

Hi Arduinoadicts, :slight_smile:

I have been doing a few Arduino projects, and I am familiar with Arduino, I use visual micro and visual studio 2019.

One of my projects it is becoming very big (using Arduino mega), I want to have all the code more modulated and I made a few classes for each dedicated things, for instance I have an abstract class game with 3 gametype classes inhering from game and also I have classes for the mp3 player, leds, lcd etc...

My question is which is the best way to access from one of this classes to the others? Using extern? I don't know if we can do extern from an ino file, should I move all to a main class and do extern from that class? or should a write a singleton pattern?

I had all the declarations on my main Ino file, at that was working fine but but now that all is modulated I don't know how to access the variables from inside the child classes

For instance:

Ino file (Main file with all the initialization of other classes)

LedManager - FXLibrary

  • LedDebugger
    Mp3Player
    Game- Game 1
    Game 2
    Game 3
    SoundsClass - Piano
  • FX
    BatteryStatus
    LCD

For instance, what is the best way in Arduino to play the methodes inside Mp3Player from Game1 class? Or the lcdprint methode incide LCD class from Piano

Thank you very much,
David

My question is which is the best way to access from one of this classes to the others?

Any class that wants to give up data should provide a get method.

The whole idea behind object oriented programming is encapsulation. A class does something. How it does it should be completely irrelevant to any other class.

If an instance of one class thinks it needs data from another instance, the other instance needs to provide a way for the first instance to get the data it needs.

Any other approach is simply wrong - global data, extern statements, etc.

or should a write a singleton pattern?

If a singleton was appropriate, you'd know it.

For instance, what is the best way in Arduino to play the methodes inside Mp3Player from Game1 class?

The Mp3Player class needs to provide method(s) that the Game1 instance can call. Of course, the Game1 instance needs to know that there is, somewhere, an instance of the Mp3Player class.

Or the lcdprint methode incide LCD class from Piano

First, you have to answer the question of how does an instance of the Piano class know that there is an instance of the LCD class lurking around? When you know that, having the Piano instance call the LCD instance's method(s) is just like calling any other method.

If everything is instantiated in the main ino file, then you can pass the instance of "mp3player" to "game1" as an argument to the contructor or to a "setter".

#incude "mp3player.h"

class Game1 {
private:
  mp3player *mp3;
public:
  //Constructor calls the setter
  Game1(mp3player *player) { setPlayer(player); }

  //The getter
  mp3player* getPlayer() { return mp3; }

  //The setter, usually returns what gets replaced
  mp3player* setPlayer(mp3player *player) { mp3player prev = mp3; mp3 = player; return prev; }
}

This is the usual design pattern when dealing with shared instances and I would recommend this approach since it would allow different instances / subclasses of the player to be used with different instances of the game.

Singletons could also be used, but they should only be used if there is never going to be any more than one instance of a given class. An example of a singleton could be a "shared preferences" class where the same set of configurations are to be accessed/modified throughout an application / sketch.

The Mp3Player class needs to provide method(s) that the Game1 instance can call. Of course, the Game1 instance needs to know that there is, somewhere, an instance of the Mp3Player class.
First, you have to answer the question of how does an instance of the Piano class know that there is an instance of the LCD class lurking around?

Thanks PaulS, that is exactly what I am asking for, the best way to get the instance of the class from the other classes :wink:

This is the usual design pattern when dealing with shared instances and I would recommend this approach since it would allow different instances / subclasses of the player to be used with different instances of the game.

Thank you Danois90,

I thought about sending using arguments but didn't look that nice to me because I have to send a parameter of all my other needed classes.

For instance my game class has to know aobut the blueTooth, the Leds, the LCD, the beeper, buttons, infrared..., it looks a lot of parameters to send to the constructor, isn't?

Singletons could also be used, but they should only be used if there is never going to be any more than one instance of a given class. An example of a singleton could be a "shared preferences" class where the same set of configurations are to be accessed/modified throughout an application / sketch.

I used singletons in Unity I am familiar with them, is why I was considering to use one here as I could access all them in theory.

Do you think in that case still better to send the parameters than making a singleton?

I also have some other questions about this ino files, is possible to get rid completly from the ino file and dont use it at all?
I have all my main inicialization in a .ino file, is that approach better or should I do it in a cpp file with a header and if the .ino file is needed only call the class on the setup() and the update methode on loop()

snoche:
For instance my game class has to know aobut the blueTooth, the Leds, the LCD, the beeper, buttons, infrared..., it looks a lot of parameters to send to the constructor, isn't?

Not really. But, if you don't like it, use individual setters as suggested. Maybe keep an internal flag that won't let the class do anything until completely configured.

I have seen "lots" of game code where initializers are used to do the trick, it could be something like:

GameLevel level = new GameLevel_1();
level->init(keybord, mouse, sound, display);
level->play();
level->release();

I would opt for something like this due to the flexibility it imposes. IMO are singletons a pretty rigid structure and I would preserved them for rigid features.

Ok, thanks I will try that aproach as looks easier to implement too.

Thank you