Click here to Skip to main content
Click here to Skip to main content

Low coupling and high cohesion in C++ applications

, 9 Jun 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
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.

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.

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:

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:
  • 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:

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)

Share

About the Author

James_Carter
Software Developer (Senior)
United States United States
CppDepend lead developer.

Comments and Discussions

 
GeneralMy vote of 5 Pinmemberbubaidada25-Apr-13 9:13 
Questionquestion PinmemberDan page12-Apr-13 3:42 
GeneralMy vote of 5 Pinmemberajay_garg20-Oct-12 18:10 
GeneralMy vote of 4 PinmemberPeteBarber10-Jan-12 1:19 
GeneralWell done! PinmemberTimetheos14-Jun-10 12:29 
GeneralReferences PinmemberFredrik Bornander10-Jun-10 7:15 
GeneralRe: References PinmemberIssam Lahlali10-Jun-10 8:06 
GeneralRe: References PinmemberPascal Ganaye22-Jun-10 0:30 
We'll let you go on that one then... Smile | :)
GeneralC++ Design Pinmemberfbnmike9-Jun-10 12:48 
GeneralRe: C++ Design Pinmember aphazel 死神12-Jun-10 5:30 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.1411023.1 | Last Updated 9 Jun 2010
Article Copyright 2010 by James_Carter
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid