tags:

views:

253

answers:

7

Hi

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!

+4  A: 

This sounds like a job for the Singleton design pattern.

scheibk
Maybe, but that is not the question.
Martin York
Why does this have 8 up votes. Its a potential idea, but it's not a particular good idea. There is not enough information in the question to get to that particular conclusion.
Martin York
@Martin: Helped too keep the up votes down :-)
rstevens
+1, anti singleton crusade is getting silly
Daniel
+9  A: 

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.

Michael Myers
So you mean that I should pass the object into each of the methods of a class that require the shared object? Maybe I should have mentioned that the 4 classes are inherited classes where I obviously need the same signature for the different methods...
No, I meant to pass the object into the constructor and let the class keep track of it.
Michael Myers
Depending on whether the collaboration between the objects is conditional or not, you can either pass it in every call to the methods or to the constructor.
jeyoung
+1  A: 

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.

Mark Roddy
A: 

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();  
  }  
}
Tiggerizzy
-1 on the singleton and the Java
Yuval A
@Yuval A: This is tagged Java, after all.
Michael Myers
Yes, it was OO in general but would be nice if it could be done in C++
+4  A: 

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);  
    ...   
};
Colo
A: 

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.

AProgrammer
A: 

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
Tom Dalling