c++design-patternsrefactoringcode-duplication

Suggestion needed to remove duplicate class, without changing #define depends on that class static object


There is a duplicate class implementation in two projects, which are using C++. When i tried to merge the minor differences of both into a single class, i faced a blocker as the #define's in the class are having direct dependency on static object which is created out of this class on both projects as shown below.

From Project1

enum severity_type
{
    debug = 1,
    error,
    warning
};


template< typename T >
class logger
{
public:
    logger(const std::string& name);

};

#define LOGGING_LEVEL_1
static logger< file_log_policy > log_inst(GetAppDataPath()+ "\\Logs\\backup.log");
#ifdef LOGGING_LEVEL_1
#define LOG log_inst.print< severity_type::debug >
#define LOG_ERR log_inst.print< severity_type::error >
#define LOG_WARN log_inst.print< severity_type::warning >
#else
#define LOG(...) 
#define LOG_ERR(...)
#define LOG_WARN(...)
#endif

#ifdef LOGGING_LEVEL_2
#define ELOG log_inst.print< severity_type::debug >
#define ELOG_ERR log_inst.print< severity_type::error >
#define ELOG_WARN log_inst.print< severity_type::warning >
#else
#define ELOG(...) 
#define ELOG_ERR(...)
#define ELOG_WARN(...)
#endif

From Project 2

enum severity_type
{
    debug = 1,
    error,
    warning
};


template< typename T >
class logger
{
public:
    logger(const std::string& name);

};

#define LOGGING_LEVEL_1
static logger< file_log_policy > log_inst(GetAppDataPath()+ "\\Logs\\restore.log");
#ifdef LOGGING_LEVEL_1
#define LOG log_inst.print< severity_type::debug >
#define LOG_ERR log_inst.print< severity_type::error >
#define LOG_WARN log_inst.print< severity_type::warning >
#else
#define LOG(...) 
#define LOG_ERR(...)
#define LOG_WARN(...)
#endif

#ifdef LOGGING_LEVEL_2
#define ELOG log_inst.print< severity_type::debug >
#define ELOG_ERR log_inst.print< severity_type::error >
#define ELOG_WARN log_inst.print< severity_type::warning >
#else
#define ELOG(...) 
#define ELOG_ERR(...)
#define ELOG_WARN(...)
#endif

Here, you can observe as we have two static objects from two projects.

I want to have these static objects while the program is running. But the major bottle neck while i try to merge these files are the #define's from Project 1

#define LOGGING_LEVEL_1
static logger< file_log_policy > log_inst(GetAppDataPath()+ "\\Logs\\backup.log");
#ifdef LOGGING_LEVEL_1
#define LOG log_inst.print< severity_type::debug >
#define LOG_ERR log_inst.print< severity_type::error >
#define LOG_WARN log_inst.print< severity_type::warning >
#else
#define LOG(...) 
#define LOG_ERR(...)
#define LOG_WARN(...)
#endif

and project2

#define LOGGING_LEVEL_1
static logger< file_log_policy > log_inst(GetAppDataPath()+ "\\Logs\\restore.log");
#ifdef LOGGING_LEVEL_1
#define LOG log_inst.print< severity_type::debug >
#define LOG_ERR log_inst.print< severity_type::error >
#define LOG_WARN log_inst.print< severity_type::warning >
#else
#define LOG(...) 
#define LOG_ERR(...)
#define LOG_WARN(...)
#endif

these #define's like LOG, LOG_ERR are used in thousands of places in code. can you suggest a better approach here, without modifying the #define's where i can merge these classes and use a single class for both projects.

i want the #define's to be unchanged and the duplicate classes to be merged into one, and the static objects should also exist.

Can someone suggest a better approach where i can refactor this code without touching #define's


Solution

  • Restating the problem to make sure I understand: you have two separate codebases (call them backup and restore) where your cpp files have a #include "logger.h", which is the code you show above. You now want to merge both codebases into a single codebase.

    Then, by construction, every .cpp file only ever #includes one or the other logger.h. Furthermore, every .cpp file will have its own copy of log_inst because you declared it as a static variable in the header.

    I suggest extracting everything but the static variable into a logger-common.h.

    You can then have a logger-backup.h with the following contents:

    #include "logger-common.h"
    static logger< file_log_policy > log_inst(GetAppDataPath()+ "\\Logs\\backup.log");
    

    and vice versa for logger-restore.h.

    This still means you need to touch up the #includes for your codebases, but that is an order of magnitude less work than changing every LOG call.

    If you really don't want to do that either I suppose you can play with the order of include directories for the files in each codebase to make sure they see "their" logger.h first, but it will horribly confuse your IDE and coworkers.