A question about c++ design and efficiency… Imagine this code –
Database db;
class SmallObject
{
private:
/* Some small amount of data and functions */
public:
/* Constructor, more functions */
void fn1() { /* Code that uses global db to do it's job */ }
void fn2() { /* Code that uses global db to do it's job */ }
void fn3() { /* Code that uses global db to do it's job */ }
void fn4() { /* Code that uses global db to do it's job */ }
};
That’s nice, efficient and works well. However the database is global state which is bad. It makes it very hard to test the class in isolation etc and means that SmallObject depends on a specific implementation of Database.
So I restructure it this way :-
class SmallObject
{
private:
/* Some small amount of data and functions */
public:
SmallObject(Database& db) { db_ = db; }
void fn1() { /* Code that uses global db_ to do it's job */ }
void fn2() { /* Code that uses global db_ to do it's job */ }
void fn3() { /* Code that uses global db_ to do it's job */ }
void fn4() { /* Code that uses global db_ to do it's job */ }
};
And perhaps make a factory to create them so I can use them roughly as before.
class SmallObjectFactory
{
private:
Database* db_;
public:
SmallObjectFactory()
{
db_ = new SpecificDatabaseSubclass;
}
SmallObject* create() { return new SmallObject(db_); }
};
That works too, means that my SmallObject is no longer coupled to the exact database implementatiom but is still convenient to use.
However, imagine there are 10000 instances of SmallObject. Now each one has a pointer to the same Database object in there. That’s horribly inefficient, and also I don’t feel that duplicating the data so many times is good design…
So, is there some pattern in C++ that allows me to not make Database global and yet allows me not to store duplicate data in each instance of SmallObject?
This is specifically C++ so templates etc, are fine…
If you are looking for efficiency it may well be the way you are allocating large numbers of small objects and might want to use some kind of pool.
With regards to the database, I would question your coupling and what users of your classes are doing and seeing. Ideally you do not want them to see your implementation detail, which may be an issue if your class has this private “database” member in it although you can forwardly-declare it.
Your constructor should look like:
You should also handle SmallObjectFactory properly to manage the lifetime of the underlying db member, probably making your class non-copyable or using shared_ptr.
Your other option might be to maintain a collection of small objects and perform functionality that accesses the database through the container rather than the objects. This is a common design pattern but depends on your model.