sujat
sujat

Reputation: 297

C++ Which design pattern should be used when accessing class property globally

The question is pretty simple .Currently i am working on a project which have a class lets call it ResoureceHandler.cpp . This class has some properties , method which is needed by the remaining classes . some properties like username, userid which i can get , set simply by calling resourceHandler->getUserName() or vice versa . I can think of two ways

Method 1: Make the class singleton and access the method to get , set.

Method 2 make the class and properties static and access them without any instance .

But i am not sure either of them fall into proper design . What should be the ideal way to solve this kind problem ?

Upvotes: 0

Views: 718

Answers (2)

ObliteratedJillo
ObliteratedJillo

Reputation: 5166

Rather suggesting a 3rd method. Avoid using global variables or singletons. A clean code should be the key. Use helper functions when necessary and namespaces like so. If your class is complex, use a proxy design pattern to reduce complexity of class objects and for a cleaner code.

//foo.h ( Avoid instantiating the foo class yourself)

namespace myproject { namespace part1
  {
    class foo  
    {
       string username_;
      public: 
       foo() { username_ = "foo";}
      //properties
         string get_username() const { return username_; }
      //methods
    };    

// helper functions 

  string get_username();

 }    
}

// foo.cpp

namespace myproject { namespace part1
{
  shared_ptr<foo>& get_foo()   
  {
     static shared_ptr<foo> pt;
       if( pt == nullptr)
           pt = make_shared<foo>();
       return pt; 
  }    

   string get_username()
   {
     return get_foo()->get_username();
   }
  }
}

//poo.h

namespace myproject { namespace part2
  {
    class poo  
    {
       string username_;
      public: 
         poo(){ username_ = "poo";}
      //properties
         string get_username() const {return username_;}
      //methods
    };


// helper functions 

  string get_username();

 }    
}

main.cpp

using namespace myproject;
int main()
{
  cout << part1::get_username() << endl;
  auto str2 = part2::get_username();
  return 0;
}

Upvotes: 1

user9335240
user9335240

Reputation: 1799

Well, if you want something high performance. Use either of the two methods.

But if you want good coding practice like other languages. You can try something like this:

class User {
private:
    int id;
    string name;
public:
    User(int id, const string &name): id(id), name(name) {}
    inline int getId() const { return id; }
    inline const string &getName() const { return name; }

    // Make a shared object of the User class
    static shared_ptr<User> currentUser;

    static inline void logIn(int id, const string &name) {
        User::currentUser = std::make_shared<User>(id, name);
    }
};

shared_ptr<User> User::currentUser = 0;

void doSomethingLengthyWithUser(shared_ptr<User> user) {
    static mutex mut; // The lock, for printing

    // Simulate long running process
    std::this_thread::sleep_for(std::chrono::milliseconds(3000));

    // This (lock block) is only to make the printed output consistent
    // Try to remove the block, and use the "cout" line only, and see.
    {
        lock_guard<mutex> l(mut);
        cout << "Done it with: " << user->getName() << endl;
    }
}

int main() {

    // Login first user
    User::logIn(1, "first");
    cout << "Logged in: " << User::currentUser->getName() << endl;

    // Now, we want to do something lengthy with the current user.
    // If you were in a different class, you could use the static variable
    std::thread doWithFirst(doSomethingLengthyWithUser, User::currentUser);

    // Login the second user
    User::logIn(2, "second");
    cout << "Logged in: " << User::currentUser->getName() << endl;

    // Do the lengthy operation with the second also
    std::thread doWithSecond(doSomethingLengthyWithUser, User::currentUser);


    // Wait for the second thread to end;
    doWithSecond.join();

    return 0;
}

Why all this?

If there was a lengthy user-related operation, and you suddenly mutate the currentUser. Being a shared_ptr this makes it still unreleased and unmutated INSIDE THE OPERATION, while the static variable will refer to the new one. Also an alternative approach is using copying, but in C++ it may cause some performance problem.

Upvotes: 1

Related Questions