I want to store parameters and handles of objects in a single place (C++) so that every other object in this project can get these information and they only need to be changed in one place. For example I have some strings and a (single!) object which handles an external device. Now different objects all over the project should be able to handle the external device by using the same instance of the controlling object.
What is the best way to implement this? Is there a pattern? Should I have one static class which initializes all these objects and variables and gives a reference of it to objects when asked for? Or should I hand over the reference to these objects all the time - what I do at the moment and really don't like.
Thanks!
As https://stackoverflow.com/users/2493903/undercover already said, singleton is what you need.
Example:
class Foobar
{
public:
static Foobar & singleton()
{
static Foobar foo;
return foo;
}
private:
Foobar();
Foobar( const Foobar & ); // don't implement
Foobar & operator=( const Foobar & ); // don't implement
};
You should consider Singleton, like it was said, but some supplement should be added IMO.
Using Singleton should be well defined in design to avoid mess in project, otherwise it becomes global variable with its almost all disadvantages(almost, because it's easier to make Singleton thread-safe ;))
Personally I prefer dependency injection, because when someone have to do more work than
Foo::getInstance().doSomething();
then he will more likely consider if he really needs to use this class here.
Related
class AA
{
public:
AA ();
static void a1 ();
static std :: string b1 ();
static std :: string c1 (unsigned short x);
};
My class won't have different objects interacting with among themselves or with others.
Of course I need to have at least one object to call the functions of this class, so I thought of making the members static so that unnecessary object creation can be avoided.
What are the pros and cons of this design? What will be a better design?
To access to static members, you don't even need an object, just call
AA::a1()
This patterns is called "Monostate", the alternative being Singleton, where you actually create an object, but make sure it's only done once, there are tons of tutorials on how to do that, just google it.
Should members of a class be turned static when more than one object creation is not needed?
You make members of the class static when you need only one instance of the member for all objects of your class. When you declare a class member static the member becomes per class instead of per object.
When you say you need only one object of your class, You are probably pointing towards the singleton design pattern. Note that pattern is widely considered an anti pattern and its usefulness if any is dependent to specific situations.
The reason you mention in Q is no way related to whether you should make a member static or not.
Your class has no data members, so I don't see any good reason to use a class at all:
namespace AA
{
void a1 ();
std :: string b1 ();
std :: string c1 (unsigned short x);
};
Of course I need to have at least one object to call the functions of this class
That's not true. You can call static member functions without an instance of the class.
A note on the Singleton pattern: it has a bad reputation, it is often mis-used, and in my experience it is only very rarely useful. What it does is enforce that there can only be one instance of the class, and that this instance is globally accessible.
People often think, "I only need one instance, therefore I should use Singleton", especially when Singleton is the first Capitalized Design Pattern they're introduced to. This is wrong -- if you only need one instance, create one instance and use it. Don't unnecessarily limit all future users of the class to only create one instance. Don't unnecessarily create shared global state. Both things make your code less flexible, harder to use in different ways and therefore in particular harder to test. Some people would argue that for these reasons, Singleton is strictly never useful.
In this case you don't seem to need even one instance. If that's the case I'd use free functions as above.
Let us say that I have the classes M, A, B, C. M is the main class of my application (that is the one that does most of the job) and has this structure
class M {
public:
// Something here.
private:
Conifg config;
A a;
std::vector<B> bs;
const C* c;
};
In a main I create an instance m of class M and I want to set my config object, say by reading it from a file. The configuration object is nothing special, it could be a protocol buffer or a simple struct.
Now, I want a, b and c to be able to access the config object, because there are some global settings that they need. These settings are global, they do not change, and are the same for each instance of A, B and C (and M). What I am currently doing, is having a static field in each class A, B and C and I am setting a copy of the configuration object for each instance of these classes. I do not want these classes to know of the existence of M. Is this the best solution? Should I perhaps think of a global config variable?
Just pass the Config object to the A, B and C constructors (specifically, pass a reference to the Config object which is stored in M.
That gives you:
testability (you can easily swap out the config object for testing purposes
ease of reuse (you don't have "invisible" dependencies on globals that just have to be there. All A, B and C needs in order to exist are what they're given in their constructors
flexibility (you can create different config objects to pass to different classes, if you need to)
readability, because the person reading your code doesn't have to wonder "where does the config object come from? Who else might have changed it? Can I be sure it's been initialized at this point?". The classes A, B and C are self-contained, and can be read and understood in isolation.
But whatever you do, don't use a singleton, and try to avoid static/global data in general.
I would advice you to use an additional static class for configuration, instead of static fields in all the classes, where you include its header in the places you want.
Implement a static constructor where you initialize all the data you want in the static members. I think this would be a better solution.
I personally would rather somehow pass that config object to A B C than use global/static objects.
What about passing it (it's reference) as an argument upon construction of a b c, or setting it later via set_config() call?
I've found the most maintainable solutions for problems like these, are to use static function. If you use some object interface, hide it behind these functions.
Here is an example.
namespace config {
// public interface that is used a lot
bool GetConfigValue(const std::string &key, std::string &val);
}
namespace config {
namespace detail {
// detail interface that is used for setup and tear down
class Config {
public:
virtual ~Config() {}
virtual bool get(const std::string &key, std::string &val) = 0;
};
void RegisterConfig(Config *cfg);
void ResetConfig();
}}
Honestly, you'll have to change the interface eventually, and it's going to suck. The more you expose throughout the code, the higher risk it will be. So keep it simple.
As background, this is a cross-cutting concern which are typically annoying to deal with. You really don't want to pass these sorts of things around to your objects. Research into aspect oriented programming may be interesting, as they talk about the subject a lot.
I have probably a quite simple problem but I did not find a proper design decision yet.
Basically, I have 4 different classes and each of those classes has more than 10 methods.
Each of those classes should make use of the same TCP Socket; this object keeps a socket open to the server throughout program execution. My idea was to have the TCP obejct declared as "global" so that all other classes can use it:
classTCP TCPSocket;
class classA
{
private:
public:
classA();
...
};
class classB
{
private:
public:
classB();
...
};
Unfortunately, when declaring it like this my C++ compiler gives me an error message that some initialized data is written in the executable (???). So I am wondering if there is any other way I could declare this TCP object so that it is available for ALL the other classes and its methods?
Many thanks!
I'd suggest you keep the instance in your initialization code and pass it into each of the classes that needs it. That way, it's much easier to substitute a mock implementation for testing.
This sounds like a job for the Singleton design pattern.
The me sounds more for the right time to use Dependency Injection as i tend to avoid Singleton as much as i can (Singleton are just another way for accessing GLOBLAS, and its something to be avoided)
Singleton vs Dependency Injection has been already discussed on SO, check the "dependency injection" tag (sorry for not posting some links, but SO doens't allow me to post more than one link being a new user)
Wikipedia: Dependency Injection
As per your current code example, should be modified to allow injecting the Socket on the constructor of each Class:
class classA
{
private:
public:
classA(TCPSocket socket);
...
};
class classB
{
private:
public:
classB(TCPSocket socket);
...
};
Pass the socket into the constructor of each object. Then create a separate factory class which creates them and passes in the appropriate socket. All code uses the set of objects which are required to have the same socket should then create them via an instance of this factory object. This decouples the classes that should be using the single socket while still allowing the enforcement of the shared socket rule.
The best way to go about doing this is with a Singleton. Here is it's implementation in Java
Singleton Class:
public class SingletonTCPSocket {
private SingletonTCPSocket() {
// Private Constructor
}
private static class SingletonTCPSocketHolder {
private static final SingletonTCPSocket INSTANCE = new SingletonTCPSocket ();
}
public static SingletonTCPSocket getInstance() {
return SingletonTCPSocket.INSTANCE;
}
// Your Socket Specific Code Here
private TCPSocket mySocket;
public void OpenSocket();
}
The class that needs the socket:
public class ClassA {
public ClassA {
SingletonTCPSocket.getInstance().OpenSocket();
}
}
When you have an object which is unique in your program and used in a lot of places, you have several options:
pass a reference to the object everywhere
use a global more or less well hidden (singleton, mono-state, ...)
Each approach have its drawbacks. They are quite well commented and some have very strong opinions on those issues (do a search for "singleton anti-pattern"). I'll just give some of those, and not try to be complete.
passing a reference along is tedious and clutter the code; so you end up by keeping these references in some long lived object as well to reduce the number of parameters. When the time comes where the "unique" object is no more unique, you are ready? No: you have several paths to the unique object and you'll see that they now refer to different objects, and that they are used inconsistently. Debugging this can be a nightmare worse than modifying the code from a global approach to a passed along approach, and worse had not be planned in the schedules as the code was ready.
global like approach problem are even more well known. They introduce hidden dependencies (so reusing components is more difficult), unexpected side-effect (getting the right behaviour is more difficult, fixing a bug somewhere triggers a bug in another components), testing is more complicated, ...
In your case, having a socket is not something intrinsically unique. The possibility of having to use another one in your program or to reuse the components somewhere were that socket is no more unique seems quite high. I'd not go for a global approach but a parametrized one. Note that if your socket is intrinsically unique -- says it is for over the network logging -- you'd better encapsulate it in a object designed for that purpose. Logging for instance. And then it could make sense to use a global like feature.
As everyone has mentioned, globals are bad etc.
But to actually address the compile error that you have, I'm pretty sure it's because you're defining the global in a header file, which is being included in multiple files. What you want is this:
something.h
extern classTCP TCPSocket; //global is DECLARED here
class classA
{
private:
public:
classA();
...
};
something.cpp
classTCP TCPSocket; //global is DEFINED here
Sorry for reposting this, but for some reason I can not add comments to my older
post. Some people wanted to know the exact error message I get when trying to do
the following:
I have probably a quite simple problem but I did not find a proper
design decision yet. Basically, I have 4 different inherited classes and
each of those classes has more than 10 methods.
Each of those classes should make use of the same TCP Socket; this
object keeps a socket open to the server throughout program execution.
My idea was to have the TCP obejct declared as "global" so that all
other classes can use it:
classTCP TCPSocket;
class classA
{
private:
public:
classA();
virtual void method1();
...
};
class classB
{
private:
public:
classB();
virtual void method1();
...
};
and so on for classC and classD...
Unfortunately, when declaring it like this my Symbian GCC-E compiler gives me the
following error message
elf2e32 : Error: E1027: ELF File contains initialized writable data.
So I am wondering if there is any other way I could declare this
TCP object so that it is available for ALL the other classes and its
methods? classA() is the first method that will be called when
initialising this subsystem.
Many thanks!
There is very elegant way to retrieve static instances on demand.
classTCP& SingletonInstance()
{
static classTCP instance;
return instance;
}
Idea is using c++ feature to initialize local static variables only on demand.
You can support a class-wide static member by allowing both classA and classB to inherit from the same parent.
class BaseTCP {
static classTCP tcp;
// ...
};
class classA : BaseTCP {
// ...
};
class classB : BaseTCP {
// ...
};
Now classA and ClassB both share the same static member. The stipulation is that you now have to declare the static member outside of the BaseTCP class someplace, similar to:
classTCP BaseTCP::tcp;
Depending on your situation, this may be overkill...
Instead of using singletons, why don't you just create a classTCP instance and pass references to the other objects, each of which owns a reference (or pointer) to the single instance of classTCP.
This offers a much more flexible design - I think singletons generally suck and have much more limited use that generally believed. If you use a singleton, your classes classA, classB etc... have no option but to use the singleton instance. Using a more standard object composition design, you free the whole thing up.
Ask yourself questions like, what if I want the application to talk to >1 server? or what if I want to write some unit test code for classA? Writing unit test code for networking applications is a lot easier when you don't need to use real sockets but can use dummy ones that simply hold the chunks of data in ram. Add a comment if you want an example, because I'm off for lunch now:)
Doing it the way I suggest does not add significant complexity to the overall design but makes it much more open.
A Singleton pattern.
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.