Here we continue with explaining some of the mistakes commonly made in Object Oriented design, and the good practices that are often ignored. This article is focused on code maintainability and on improving cooperation with people working at the same project.

Encouraging class dependencies

Having a lot of (mutual) dependencies in the code is quite typical of Spaghetti Code, and it’s definitely something we want to avoid, in order to keep our design neat, improve maintainability and ensure ease of collaboration with colleagues. What do I mean by “class dependencies”? Let’s continue the example from the last article, and suppose we have a certain class GuiManager which, at some points, wants to generate some reports. Let’s introduce now a certain ReportManager, which is a class responsible for generating reports. We have two types of report: TableReport, and ChartReport. They look like this:

class TableReport {
    public:
        void report()  {
            // do something
        }
};

class ChartReport {
    public:
        void report()  {
            // do something
        }
};

This means that the ReportManager will have to look something like this:

class ReportManager {
    public:
        void reportAll() {
            m_tableReport.report();
            m_chartReport.report();
        }

    private:
        TableReport m_tableReport;
        ChartReport m_chartReport;
};

There are several problems in this implementation. First of all, If the guy responsible for the TableReport one day wakes up, and decides that the method report() should rather be named generate(), he will not only be allowed to just change that and commit to the repository, but this will break the ReportManager! So after a few hours, the guy responsible for the ReportManager checks out from the repository, builds, and finds out that all the times he has used the TableReport need to be changed. Of course this is something we don’t want to happen.

The usual approach to this, is using an Abstract Base Class (ABC), which is a very robust way to sort out problems like this. Let’s see come code:

class Report {
    public:
        virtual void report() = 0;
};

class TableReport : public Report {
    public:
        void report()  {
            // do something
        }
};

class ChartReport : public Report {
    public:
        void report()  {
            // do something
        }
};

Report is ourABC, and with it we are literally forcing the people who write TableReport and ChartReport to write a method named report(). So, this way we broke one dependency: the ReportManager doesn’t need to worry about the way every single report will call the method: it’s sure that a method named report() will exist.

There is, tho, another dependency. If somebody writes a new report, say XmlReport, this will need modifications to the ReportManager, because our logic so far implies that the ReportManager knows about all the reports. So, if we’re not the maintainers of the ReportManager (because maybe it’s in some different library, written by someone else, and we don’t have access to the code), we will have to go ahead and ask the rightful maintainer to modify the code. Hence, there’s an extra dependency, not structural, this time, but logical. What if the maintainer of the ReportManager gave us tools (read APIs) so that we can register our particular report to the ReportManager? Consider the following code:

class ReportManager {
    public:
        void registerReport(Report const & r) {
            m_reports.push_back(r);
        }

        void reportAll() {
            std::list::const_iterator iter;
            for(iter = m_reports.begin();
                 iter != m_reports.end();
                 ++iter)
            {
                iter->report();
            }
        }

        private:
            std::list m_reports;
};

This way, the ReportManager doesn’t have to know anything about any Report.