Click here to Skip to main content
15,860,972 members
Articles / Programming Languages / C++
Article

Low coupling and high cohesion in C++ applications

Rate me:
Please Sign up or sign in to vote.
4.73/5 (53 votes)
9 Jun 2010CPOL3 min read 97.2K   55   11
High cohesion and low coupling improves project design.

Introduction

Coupling is usually contrasted with cohesion. Low coupling often correlates with high cohesion, and vice versa. Low coupling is often a sign of a well-structured computer system and a good design, and when combined with high cohesion, supports the general goals of high readability and maintainability. The goal of this case study is to show the benefits of low coupling and high cohesion, and how it can be implemented with C++. The case study consists of designing an application that accesses a file in order to get data, processes it, and prints the result to an output file.

Solution without design

For this first solution, the design is ignored and only one a class named CDataProcessor is used to:

  • Get data from a file.
  • Process data.
  • Print the result.

And the main method invokes the methods of this class.

Image 1

Drawback of this solution

The CDataProcessor class has many responsibilities, so we can’t easily reuse the algorithm in other applications.

  • High coupling: the processing is high coupled with a console and also with a data provider.

Design refactoring

High cohesion

To improve cohesion, each responsibility must be assigned to a different class, so we need three classes:

  • CFileProvider: To get data from a file.
  • CDataProcessing: To process data, and this class can use other classes to complete processing, but to simplify the design, we consider that's sufficient for our processing.
  • CResultReporting: To report result to a file.

So each class has its own responsibility. The advantages of this design are:

  • Easy to understand classes.
  • Easy to maintain.
  • Easy to reuse classes in other applications.

Low coupling

What happens if data exists in a database rather than a file? In our last design, our application is high coupled with a file provider.

To resolve this problem, we need an interface that provide methods to get data from anywhere, and for the case of the file, we need a class that implement this interface.

For that, using NVI can be good solution. This pattern is more useful than using only abstract classes because it's possible to define a pre- and post-condition. It's a useful object-oriented programming technique, particularly at development time. Pre- and post-conditions ensure that invariants of a class hierarchy (and in general, an abstraction) are not violated at designated points during execution of a program.

In our case, we can add the IDataProvider interface.

Image 2

And CFileProvider inherits from IDataProvider to implement GetDataFromImpl, and the same design can be used for CDataProcessing and CReportResult.

Here’s the new collaboration between classes after refactoring:

Image 3

Class factory

In the latest design, the creation of concrete instances of IDataProvider, IDataProcessing, and IReportResult are created by the main method. A better approach is to assign this responsibility to a factory class, so a logic to instantiate a family of instances needed is isolated.

Controller

The orchestration between all classes is implemented in the main method. It's better to assign this responsibility to a Controller class, so we can use it in other applications.

The controller needs three classes to interact with them, so the question is how do we bind instances to the controller.

In C++, two solutions can be used:

  • Add a method named BindInstances(IDataProviderPtr,IDataProcesingPtr,IReportResultPtr).
  • Use a template so the controller will be instantiated like that:
  • C++
    CController<CFileProvider,CDataProcessor,CConsoleReport>

The difference between the two solutions is that for the first one, each Data Provider must inherit from IDataProvider, and for the second one, CFileProvider only needs the method GetData(Data&) even if it’s inherited from another class than IDataProvider.

There are many discussions between C++ gurus about using OOP or templates. Here's a good article about this tension between the two approaches.

Here’s the new collaboration between the classes after refactoring:

Image 4

Benefits of refactoring

After refactoring, this application became more flexible and we can use it for different scenarios:

  • Can get data from file, database, XML file, CSV file, …
  • Can process with many classes not just one.
  • Can report to console, file, …

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



Comments and Discussions

 
QuestionCode Download for the article is not available Pin
muzamil2k12-Apr-17 2:58
muzamil2k12-Apr-17 2:58 
GeneralMy vote of 5 Pin
iDebD25-Apr-13 8:13
iDebD25-Apr-13 8:13 
Questionquestion Pin
Dan page12-Apr-13 2:42
Dan page12-Apr-13 2:42 
GeneralMy vote of 5 Pin
ajay_garg20-Oct-12 17:10
ajay_garg20-Oct-12 17:10 
GeneralMy vote of 4 Pin
PeteBarber10-Jan-12 0:19
PeteBarber10-Jan-12 0:19 
GeneralWell done! Pin
Timetheos14-Jun-10 11:29
Timetheos14-Jun-10 11:29 
GeneralReferences Pin
Fredrik Bornander10-Jun-10 6:15
professionalFredrik Bornander10-Jun-10 6:15 
GeneralRe: References Pin
Issam Lahlali10-Jun-10 7:06
Issam Lahlali10-Jun-10 7:06 
GeneralRe: References Pin
Pascal Ganaye21-Jun-10 23:30
Pascal Ganaye21-Jun-10 23:30 
GeneralC++ Design Pin
fbnmike9-Jun-10 11:48
fbnmike9-Jun-10 11:48 
GeneralRe: C++ Design Pin
Aoi Karasu 12-Jun-10 4:30
professional Aoi Karasu 12-Jun-10 4:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.