C++ software design options, class relationships - c++

Problem:
I have totally separate software managers (software entities), for example CCarManager, CTruckManager etc.. At some point I am creating new objects for example CCar. CCar must have relationships with various separate managers, for example, with CResourceManager, CTruckManager. What is the best way to link CCar with these managers?
Solutions:
Have global software managers (Singleton or extern in header file)
[Don't like globals]
Use one global point and pass it to other obects e.g CCar(CApplication), CApplication->TrukManager(), CApplication->CarManager()...
[Doesn't seem nice, but can pass one pointer]
Pass to CCar(CCarManager *pCarManager, CTruckManager *pTruckManager....)
[Hard to extend]
Use Observer pattern e.g. CCar.Attach(CCarManager), CCar.Attach(CTruckManager);
[Easy to extend, but main focus become for dealing method calls, what parts are responsible for what etc., also lot of check's]
Factory.
class CCarFactory(CCarManager *pMngr)
{
CCar *CreateCar()
{
return CCar(m_pCarManager);
}
}
what are the other ways?

You can pass a reference to CResourceManager, CTruckManager, etc. in CCar's constructor.
CCar(const CResourceManager& resourceMgr, const CTruckManager& truckMgr):
_resourceMgr(resourceMgr), _truckMgr(truckMgr) {
//relevant construtor code here
}
This way it's easy to test with mock implementations as well. It's hard to say without knowing what the 'Manager classes do.
IMHO, classes whose names end in 'Manager' are often either poorly named (which I've done more times than I can count), or poorly designed.

If the only reason you won't use the Singleton pattern is because you don't like it, I think you might want to reconsider your approach.
Singletons are a perfect pattern for what you're trying to acheive here. You have management classes that should only have one instance and require access from many other classes.

Its hard to say without some more specifications... If CCar requires special access to the manager methods (like internal variables/methods) or vice-versa, you can declare in CCar managers as friend, or CCar as friend in those manager classes.
simple example, mind the poor member names
class CCar
{
int I;
public:
friend class CManager;
CCar(int i): I(i) {}
};
class CManager
{
int D;
public:
CManager(int i, CCar& car): D(i)
{
car.I = 5; // modify CCar instance internal member
}
};
or vice versa if its the other way around.
If a CCar instance can have multiple CCarManagers, you could set up an array of pointers to 'link' those managers to an instance of CCar. Rather than having 3 different pManager arrays, having a Manager base class, and subclassing those managers to it, will let you store all references to managers in a single array.
class Manager // etc...
class CResourceManager : public Manager
// in CCar
std::vector<Manager*> _mgrs;
// or if heap allocated
std::vector<std::shared_ptr<Manager>> _mgrs; // assuming multiple CCars can reference same manager instance
Another method could be to have a struct/class that can hold all manager references for a particular instance.
struct MgrRefs
{
std::vector<CCarManager*> _pCarMgrs;
std::vector<CResourceManager*> _pResMgrs;
// etc....
};

Related

Should I use static classes in an ECS?

Hey I am currently working on a small entity component system where there are classes like EntityManager, ComponentManager and SystemManager that are only instantiated once and heavily communicate with each other.
I created a class world which owns all the managers and acts as the center for all communication between the managers. Making all the Managers static would make a lot of things much easier, more understandable and I wouldn't even need the world class.
I know though that static classes (I know "static classes" don't exist but I mean classes with only static members) act as if they were global and global variables are Bad®.
So I wonder what is recommended to do in this case
Thanks for your answers
Che
Edit:
The World class looks like this:
class World
{
public:
EntityManager* entityManager;
ComponentManager<PositionComponent>* componentManager;
MovementSystem* movementSystem;
Entity e;
public:
World(sf::RenderWindow& window);
void update();
};
To communicate each Manager needs a pointer to the world to access the other managers. Like this world->entityManager->getEntitys()
(I suggest that the project is a game or something close to it)
I don't suggest you to make all members static. The main problem with it that you're loosing control on object's lifetime. You can't destroy and create new object at runtime easily because there is no object. For example, if you want to change a manager at runtime you'll have to implement cleanup code manually. In case of C++ objects C++ helps you with errors/warnings, default values and class members by value.
There are few popular ways to implement and use managers in gamedev:
Use Singleton pattern. In this case class have one static method that returns link to non-static object.
Pass dependencies that method requires during the method call manually.
Singleton pattern, I think, is the best way in terms of price-quality ratio for you. Despite on all criticism of this pattern it does its job well (most of game projects I saw used Singleton approach to implement manager classes).
There is an important thing I want to suggest you about this pattern. Don't use default implementation of Singleton pattern. Create methods for creating and destroying object instead of hiding it inside of getter. Here's simple example of glue code for a manager:
class Manager {
private:
static Manager* ms_manager;
public:
static void CreateManager() { ms_manager = new Manager(); }
static void DestroyManager() { delete ms_manager; }
static Manager* GetInstance() { return ms_manager; }
};
Usage is:
Manager::GetInstance()->SomeMethod();
Passing dependencies approach has its own advantages. It may sounds too difficult to pass everything in every Update method but it's not. You can create context class, set all dependencies there and pass it to every method that needs it. It's almost like your World class but it must be structure with minimum of code and no dependencies. Don't store there any game objects by value (only primitives, geometry vectors and stuff like this). It may be something like this:
struct Context {
EntityManager* entityManager;
ComponentManager<PositionComponent>* componentManager;
MovementSystem* movementSystem;
Entity* rootEntity;
};
Usage is:
GameObject::Update(Context& context) { context.entityManager->SomeMethod(); }
The point of this approach that you can tune context for some objects at runtime. For example, if you have LODs you can save in context current LOD level and change it at runtime for some objects depends on distance to the camera.

Preventing unauthorised use of components

I'm building a component system where an abstract type Component is inherited from to make components. So far, I have drawable, physical, movable and other components. All seems to go well, and in the Game class I perform the following:
void Game::init()
{
pPlayer->addComponent(pMovable);
}
void Game::processEvents()
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
pMovable->moveUp(2.f);
// etc..
pPlayer->setVelocity(pMovable->getVelocity());
}
void Game::update()
{
pPlayer->update(0);
}
void Game::play()
{
while (pWindow->isOpen())
{
// ...
processEvents();
}
}
So far, the component system is really basic and simple. The player is of type Object and whenever I call the player's update function, I also have the Object's update function also called. This should really be automated, but that will change in the future. What the real problem is this:
pPlayer can still access pMovable's velocity even if it has not added pMovable as a component. This is problematic because it means anyone can simply get the velocity from pMovable and then plug it into their object without having to add pMovable as part of their component. Now, what does tend to happen is that the movement becomes unmanaged since there is no movable component to regulate it. I term this unauthorised use of the component, and I want to develop a way by which a component can 'deny' usage of its functionality to an object it is not owned by. There are many solutions to this problem, and I need one which is efficient and practical for use. Here are mine:
Throw an exception if the client attempts to allocate a component function into its own without adding it;
Create a system by which objects and components are identified and the component keeps track of the objects it is owned by, and the objects keep track of the components it owns. Because this is a many-to-many relationship, an intermediate class that manages all this would have to be created; it also avoids a circular header inclusion.
Have a function NOT part of an object simply 'deactivated'. This would require the use of a boolean like 'componentAdded' and all functions would have to check whether the component was added or not, else the function won't do what it ought to be doing.
If you have other solutions to prevent the unauthorised use of components, please share them as I'm keen to learn from others as to how they implemented/or would implement a component system as I have done here.
You can't prevent specific classes from inheritance. It's an all or nothing proposition: any class inherits from the base or none.
The best you can hope for is to narrow the interface. For example, instead of allowing decendents of Object in a function, you may want to have a class Stationary_Object or Enemy_Object to refine the interface. This allows you to write functions that take any Enemy_Object and won't take a Stationary_Object (like a tree or wall).
Edit 1: Cheating with friends
You can allow member access by declaring the members as private and granting access to specific classes using the friend class. The problem is that the class with data will need to be modified whenever a new type of friend is created. I believe this use of friendship defeats the purpose of reusability.
Edit 2: detecting ownership
Let's say we have three classes:
class Engine;
class Car
{
Engine car_engine;
};
class Boat
{
Engine boat_engine;
};
And a function:
void Fix_Car_Engine(Engine& e)
{
}
There is no method in C++ for the Fix_Car_Engine to know that it is fixing a car engine or a boat engine. The function only knows that it has been given a generic engine to fix (or it only knows about the common Engine stuff of the variable).
This issue can be mitigated by refining or narrowing the interface:
class Car_Engine : public Engine;
class Boat_Engine : public Engine;
class Car
{
Car_Engine diesel_engine;
};
class Boat
{
Boat_Engine propellor_engine;
};
In the above example, the Engine class has two specializations: Car_Engine and Boat_Engine. The Car now has a Car_Engine member and the Boat has a Boat_Engine.
The functions can now be created to operate on special engines:
void fix_boat_engine(Boat_Engine& be);
void fix_car_engine(Car_Engine& ce);
The fix_car_engine will now only work with Car Engines. You could say that it works on any class that has-a Car Engine (as long as you pass the Car Engine member). Likewise, the fix_boat_engine function only operates on Boat Engines.
Given:
class Rocket_Engine : public Engine;
Also, this specialization prevents a Rocket_Engine from being passed to either function. The functions require specific engine types.

Guidelines to deal with class dependencies

I have a doubt on the best approach to handle a class dependency and I was hoping to have some feedback on the issue.
Let's assume I have a class to model the Earth's ionosphere
class EarthIonosphere {
// Methods that implement physical models of the Earth's ionosphere
}
To do some computations within EarthIonosphere, I might have the need to know the value of the Earth's magnetic model. Therefore I have an independent class for this:
class EarthMagneticField {
// Methods that implement physical models of the Earth's magnetosphere
}
EarthIonosphere might depend on EarthMagneticField (but not the other way round). By the way, EarthMagneticField might also be needed in other parts of the code. With this in mind I was wondering which is the best solution (in terms of re-usability and maintainability) to approach this dependency. The two options I was considering were:
EarthIonosphere contains a private/public member of class EarthMagneticField, but I am concerned on duplication in case the same EarthMagneticField has to be used in other parts of the code.
EarthIonosphere contains a std::shared_ptr that points to an object of class EarthMagneticField that has been instantiated using the new operator. This would allow me to use exactly the same object to compute the magnetic field in other parts of the code.
Do you think any of these is a viable solution in terms of "clean code"? otherwise, do you have any suggestion like some "interface" class or similar?
Many thanks!
A shared_ptr solution is certainly an idea, but I'd also think about storing a weak reference.
If there's only going to be EarthMagneticField around, you can instantiate it and then construct all other objects with a refence to it.
If EarthMagneticField is cheap to create and there is no reason to share its state with other parts of the code I might be tempted to go with option 1 and just have it has a private member of class EarthIonosphere. You could always start with this option and refactor when you find you need to.
If you do need to share EarthIonosphere, I don't see any reason to use new and allocate dynamically. I would just create one outside of EarthIonosphere and pass a reference to the constructor of EarthIonosphere:
class EarthMagneticField {
};
class EarthIonosphere {
EarthMagneticField* magnetic_field;
public:
EarthIonosphere(){EarthMagneticField& magnetic_field)
: magnetic_field(&magnetic_field) {}
};
int main() {
EarthMageneticField magnetic_field;
EarthIonosphere ionosphere(magnetic_field);
}

How to exchange data between classes?

I'm learning C++ and moving my project from C to C++. In the process, I stumbled on this problem: how to save/update variables that are in use in several classes? In C I used global variables, but it is not good for C++.
So, let's assume we have 4 classes:
class Main_Window
{
//...
void load_data_menu_selected();
}
class Data
{
//...
double *data;
}
class Load_Data
{
//...
double *get_filename_and_load();
}
class Calculate
{
//...
int do_calculation()
}
So, Main_Window is class for application's main window where it interacts with user input etc.
I want to do:
create an instance of class Data in the Main_Window
use Load_Data for loading data from file and store it in the Data
use Calculation class for doing something with read data in Data class
The question is: where I should create classes, to make Data class members available from other classes. Should I use Inheritance?
Start from observing what are possible relations between instances of two classes. Let us say a is an instance of class A and b is an instance of class B. If a uses b, class A can have as its member instance of class B (b), pointer to b (which is of type B*), or reference of b (which is of type B&). If only one method of class A uses b, you have again same three options: B, B* or B& can be method's arguments. Having B* and B& as class members suggests that a does not control b's lifetime so class A must have a method that sets these members through its parameters. The question of ownership (objects' lifetimes) has a big role in design of relationship between classes. Main relationships are briefly described in this article.
I think you only want to have a Main_Window class, and the rest should be members of that class.
class Main_Window
{
private:
DataObject windowData;
public:
void loadData(string fileName);
void calculate();
}
Inside the loadData and calculate methods, you will be able to access the same data with this->windowData . Sorry if my syntax is bad, my c++ is rusty
Typically, you would pass (const) Data& around as an argument. If do_calculation() needs a Data to work with, then it takes Data&. But I can't really be more specific or useful unless you post more of your design.
You need to know how to design in OO. Thinking in C is different from thinking in c++. You can that your classes have many methods. Well, that sound like a bad design.
I can recommend you to start with the SOLID principle.
Then start writing unit tests for your classes. TDD could help you improve your design even further.
It sounds like you should not use inheritance here. The main reason for saying so is that you have a number of classes (Window, Calculator, etc.) using or doing something to an entity (i.e. Data). Inheritance is used to denote an "is a" relationship (i.e. if A inherits from B, A "is a" B).
In this case, you use composition, which denotes a "has a" relationship. So each class takes a reference to an instance of Data, and acts upon that object.
Who owns the Data object? To share a single Data object, you might want to look into Boost shared_ptr, which allows multiple reference-counting pointers to share an object allocated with "new".

Isn't the Factory pattern the same thing as global state?

Let's say I have a class like this:
class MonkeyFish
{
MonkeyFish( GlobalObjectA & a, GlobalObjectB & b, GlobalObjectC & c);
private:
GlobalObjectA & m_a;
GlobalObjectB & m_b;
GlobalObjectC & m_c;
}
Without a factory, I need to do the following in order to instantiated a MonkeyFish.
GlobalObjectA a;
GlobalObjectB b;
GlobalObjectC c;
int main()
{
MonkeyFish * monkey_fish = new MonkeyFish(a, b, c);
monkey_fish->go();
}
On the other hand, if I have a MonkeyFishFactory, it seems like I have to do this:
GlobalObjectA a;
GlobalObjectB b;
GlobalObjectC c;
int main()
{
MonkeyFishFactory mf_factory(a, b, c);
MonkeyFish * monkey_fish = mf_factory.buildMonkeyFish("Bob");
monkey_fish->go();
}
I still have global objects.
Even if the MonkeyFishFactory itself created the GlobalObjects internally (so they are now inside the MonkeyFishFactory instead of true globals), it seems like the MonkeyFishFactory itself still needs to be a global object so that I can access it anytime I want to create a MonkeyFish.
Isn't the Factory pattern the same thing as global state in this case?
(I'm currently operating under the assumption that global state is a Bad Thing, and eliminating it is a Good Thing.)
Are you confusing concepts here?
The Factory pattern is usually applied when you are returning an instance of a concrete class that hides behind an abstract interface. The idea is that the caller will see just the interface and doesn't even have to know what the concrete type of the object is. It is all about creating an object instance based on parameters and decoupling the logic associated with deciding what object to create from the user creating the object.
What you are describing is a mixture of Singleton (or MonoState) and Factory. Your Factory has state so it cannot be made static. In this case, you will need to apply something like the Singleton pattern to control the creation of a single Factory instance with the appropriate globals hidden within it:
class IMonkeyFish {
public:
virtual ~IMonkeyFish() = 0;
virtual void go() = 0;
};
class Factory {
public:
static Factory& instance();
IMonkeyFish* createMonkeyFish();
protected:
Factory(GlobalObjectA& a, GlobalObjectB& b, GlobalObjectC& c);
private:
static Factory *theInstance;
GlobalObjectA& instanceOfA;
GlobalObjectB& instanceOfB;
GlobalObjectC& instanceOfC;
};
Factory& factory = Factory::instance();
IMonkeyFish* fishie = factory.createMonkeyFish();
fishie->go();
The Singleton pattern governs the creation of the factory instance. The Factory pattern hides the details surrounding the creation of objects that implement the IMonkeyFish interface. The Good Thing (TM) is the hiding of the global state and decoupling of the MonkeyFish concrete details from creating an instance.
The usage or correctness of using the Singleton stuff is a whole other issue though. There are probably a bunch of threads floating around about that as well.
Global state is not in-and-of-itself a Bad Thing. Public global state is a Bad Thing. The Factory pattern helps encapsulate global state, which is a Good Thing.
There are no global state in the Factory. It just creates objects.
Since it not any state in the factory. It's OK to be global.
You don't have to leave global objects. Monkey fish factory should create those GlobalOjectA|B|C on demand. Using switch or if inside method to determine which one.
You have encapsulated control over creation of objects in a factory. You want your instantiation details to be hidden away, not reproduced everywhere you need a new MonkeyFish. Think about testing, Single Responsibility, and the Law of Demeter. Why should your class that wants to use a MonkeyFish need to know anything about the work it takes to build one. What if you want to test MonkeyFish? How would you do it if you didn't have creation details encapsulated?
The job of a factory class is to instantiate an object and pass it back to the caller; not to pick which global instantiated object to use. So, your factory example is incorrect. It should be:
int main()
{
MonkeyFish * monkey_fish = MonkeyFishFactory::buildMonkeyFish("Bob");
monkey_fish->go();
}
Notice, no global objects, and MonkeyFishFactory is not instantiated.
I think you are thinking of the Singleton Pattern, not the Factory Pattern. In the singleton pattern you only have on instance of a class which basically makes it the equivalent of a global object except there is no global variable attached to it.
You should state your constraints and requirements if you want to get a good answer. The most important thing to get a good answer is knowing what question to ask.
In the code snippets you provided you have decided to use globals, but that has nothing to do with whether you use a Factory or not. If you use a factory that still depends on those globals, then you just have another piece of code to pile up with the rest.
Try to state clearly what you are trying to achieve and you will probably get a better answer.