High Cohesion vs. Low Cohesion in Software Design

When designing software systems, the concept of cohesion plays a crucial role in determining the quality and maintainability of your code. Cohesion refers to how closely related the responsibilities of a single module or class are. Understanding the difference between high cohesion and low cohesion is essential for writing clean, robust, and scalable code.

In this blog post, we’ll explore what cohesion means, compare high and low cohesion, and provide practical examples to illustrate these principles.


What is Cohesion?

Cohesion measures how well the parts of a module or class fit together to achieve a single purpose. It reflects the degree to which the responsibilities of a class or module are focused and aligned.

Types of Cohesion:

  1. High Cohesion:
    • A module or class has a clear, well-defined responsibility.
    • All methods and properties work toward a single, unified goal.
  2. Low Cohesion:
    • A module or class is responsible for unrelated tasks.
    • The code becomes harder to understand, maintain, and test.

High Cohesion

Characteristics of High Cohesion:

  • Each module or class focuses on a single responsibility.
  • Follows the Single Responsibility Principle (SRP) from SOLID design principles.
  • Promotes maintainability, testability, and readability.

Example of High Cohesion:

Here’s a UserService class designed with high cohesion:

public class UserService
{
    private readonly IUserRepository _userRepository;
    private readonly IEmailService _emailService;

    public UserService(IUserRepository userRepository, IEmailService emailService)
    {
        _userRepository = userRepository;
        _emailService = emailService;
    }

    public User GetUserById(int id)
    {
        return _userRepository.GetById(id);
    }

    public void RegisterUser(User user)
    {
        _userRepository.Add(user);
        _emailService.SendWelcomeEmail(user.Email);
    }
}

Why It’s High Cohesion:

  • The UserService class handles user-related functionality only.
  • Responsibilities like database access and email sending are delegated to other classes, adhering to SRP.

Benefits of High Cohesion:

  • Easier Maintenance: Changes are localized to specific classes.
  • Better Testability: Focused responsibilities make it easier to write unit tests.
  • Improved Reusability: Components can be reused in other parts of the system.

Low Cohesion

Characteristics of Low Cohesion:

  • A single module or class takes on multiple unrelated responsibilities.
  • Violates the Single Responsibility Principle.
  • Leads to tightly coupled and harder-to-maintain code.

Example of Low Cohesion:

Here’s an example of a UserManager class with low cohesion:

public class UserManager
{
    public User GetUserById(int id)
    {
        // Logic to fetch user from database
        Console.WriteLine("Fetching user from database");
        return new User { Id = id, Name = "John Doe" };
    }

    public void SendEmail(string email, string message)
    {
        // Logic to send an email
        Console.WriteLine($"Sending email to {email}: {message}");
    }

    public void Log(string message)
    {
        // Logic to log a message
        Console.WriteLine($"Log: {message}");
    }
}

Why It’s Low Cohesion:

  • The UserManager class handles database operations, email sending, and logging, which are unrelated responsibilities.
  • Violates SRP by mixing different concerns.

Drawbacks of Low Cohesion:

  • Difficult to Maintain: A change in one responsibility may unintentionally affect others.
  • Harder to Test: Writing focused unit tests is challenging when a class does too much.
  • Poor Reusability: The class is tightly coupled and cannot be easily reused elsewhere.

Key Differences Between High and Low Cohesion

AspectHigh CohesionLow Cohesion
FocusSingle, well-defined responsibilityMultiple, unrelated responsibilities
MaintainabilityEasy to maintain and extendDifficult to maintain and extend
TestabilityEasy to test in isolationHard to test due to mixed concerns
ReusabilityHigh reusability of focused componentsLow reusability due to tight coupling

How to Achieve High Cohesion

  1. Follow the Single Responsibility Principle (SRP):
    • Ensure each class or module focuses on one responsibility.
  2. Use Abstraction:
    • Delegate unrelated responsibilities to different interfaces or classes.
  3. Refactor Often:
    • Regularly review your code to identify and separate mixed responsibilities.
  4. Leverage Design Patterns:
    • Patterns like Factory, Strategy, and Observer can help separate concerns.

Real-World Example: Refactoring to High Cohesion

Before Refactoring (Low Cohesion):

public class OrderManager
{
    public void PlaceOrder(Order order)
    {
        Console.WriteLine("Saving order to database");
        Console.WriteLine("Sending order confirmation email");
        Console.WriteLine("Logging order details");
    }
}

After Refactoring (High Cohesion):

public class OrderService
{
    private readonly IOrderRepository _orderRepository;
    private readonly IEmailService _emailService;
    private readonly ILogger _logger;

    public OrderService(IOrderRepository orderRepository, IEmailService emailService, ILogger logger)
    {
        _orderRepository = orderRepository;
        _emailService = emailService;
        _logger = logger;
    }

    public void PlaceOrder(Order order)
    {
        _orderRepository.Save(order);
        _emailService.SendOrderConfirmation(order.Email);
        _logger.Log("Order placed successfully");
    }
}

Conclusion

Cohesion is a fundamental principle of clean code and software design. High cohesion results in maintainable, testable, and reusable code, while low cohesion can lead to tightly coupled, hard-to-manage systems. By following best practices like SRP, abstraction, and refactoring, you can ensure your codebase remains flexible and easy to work with.

Keep these principles in mind as you design and refactor your applications, and you’ll build systems that stand the test of time.

Avatar von admin