Question

I'm coding a long-running, multi-threaded server in C++. It receives requests on a socket, does database lookups and returns responses on a socket.

The server reads various run information from a configuration file, including database connectivity parameters. I have to use a database abstraction class from the company's code library. I don't want to wait until trying to do the DB search to lazy instantiate the DB connection (due to not shown complexity and the need for error exit at startup if DB connection cannot be made).

My problem is how to get the database connection information down into the search class without doing any number of "ugly" or bad OOP things that would technically work. I want to learn how to do this right way.

Is there a good design pattern for doing this? Should I be using the "Parameterize from Above" pattern? Am I missing some simpler Composition pattern?

    // Read config file.
    // Open DB connection using config values.

    Server::process_request(string request, string response) {
        try {
            Process process(request);
            if (process.do_parse(response)) {
                return REQ_OK;
            } else {
                // handle error
            }
        } catch (..,) {
            // handle exceptions
        }
    }

    class Process : public GenericRequest {
    public:
        Process(string *input) : generic_process(input) {};
        bool    do_parse(string &output);
    }

    bool Process::do_parse(string &output) {
        // Parse the input request.
        Search search;      // database search object
        search.init( search parameters from parsing above );

        output = format_response(search.get_results());
    }

    class Search {
        // must use the Database library connection handle.
    }

How do I get the DB connection from the Server class at top into the Search class instance at the bottom of the pseudo-code above?

Was it helpful?

Solution

It seems that the problem you are trying to solve is one of objects dependency, and is well solved using dependency injection.

Your class Process requires an instance of Search, which must be configured somehow. Instead of having instances of Process allocating their own Search instance, it would be easier to have them receive a ready made one at construction time. The Process class won't have to know about the Search configuration details, and thus an unecessary dependency is avoided.

But then the problem cascades up to whichever object must create a Process, because now this one has to know that configuration detail! In your situation, it is not really a problem, since the Server class is the one creating Process instances, and it happens to know the configuration details for Search.

However, a better solution is to implement a specialized class - for instance DBService, which will encapsulate the DB details acquired from the configuration step, and provide a method to get ready made Search instances. With this setup, no other objects will depend on the Search class for its construction and configuration. As an added benefit, you can easily implement and inject a DBService mockup object which will help you build test cases.

class DBSearch {
    /* implement/extends the Search interface/class wrt DB */
};

class DBService {
    /* constructor reads up configuration details somehow: command line, file */

     Search *newSearch(){
         return new DBSearch(config); // search object specialized on db
     }

};

The code above somewhat illustrates the solution. Note that the newSearch method is not constrained to build only a Search instance, but may build any object specializing that class (as for example the class DBSearch above). The dependency is there almost removed from Process, which now only needs to know about the interface of Search it really manipulates.

The central element of good OOP design highlighted here is reducing coupling between objects to reduce the amount of work needed when modifying or enhancing parts of the application,

Please look up for dependency injection on SO for more information on that OOP design pattern.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top