Design Concepts  «Prev  Next»
Lesson 5Coupling
ObjectiveDefine coupling.

Coupling and Object Coupling Decisions

How does one decide which method belongs to a class when defining "coupling"?
When defining "coupling" in object-oriented programming (OOP), deciding which method belongs to a class revolves around minimizing interdependencies between classes while maximizing cohesion within each class. Here's a structured approach to guide the decision:
  1. Understand Coupling and Cohesion
    • Coupling: Measures the degree of dependency between classes. Lower coupling is desirable as it makes the system more modular and easier to maintain.
    • Cohesion: Measures how closely related the methods and data within a single class are. Higher cohesion is desirable because it ensures that a class has a single, clear purpose.
  2. Focus on Responsibility (Single Responsibility Principle)
    • Assign methods to the class that logically "owns" the responsibility related to that method. A class should encapsulate data and behaviors directly related to its purpose.
    • If a method manipulates a class's internal state or data, it likely belongs to that class.
    • Example:
      class Account {
      private:
          double balance;
      public:
          void deposit(double amount);
          void withdraw(double amount);
          double getBalance() const;
      };
                      
      Methods like deposit and withdraw belong to Account because they directly modify its internal state (balance).
  3. Minimize Dependencies
    • Methods that require significant knowledge of another class's implementation indicate tight coupling and are candidates for refactoring.
    • If a method requires extensive data from another class, consider whether the functionality should be moved closer to that class.
    • Example of High Coupling:
      void processPayment(Account account) {
          double balance = account.getBalance();
          if (balance > 0) {
              account.withdraw(100);
          }
      }
                      
      This could be refactored to let Account handle its logic:
      class Account {
      public:
          void processPayment(double amount);
      };
                      
  4. Use the Law of Demeter
    • A method in one class should not "reach through" another class to access third-party objects or data. This avoids "train wreck" code and keeps coupling low.
    • Ensure methods only interact with their immediate collaborators.
    • Violates Law of Demeter:
      customer.getAccount().getBalance();
                      
      Instead, encapsulate the logic within the appropriate class.
  5. Encapsulate Behavior Where Data Lives
    • Place methods in the class that has the data they operate on. This principle supports low coupling and high cohesion.
    • Avoid creating utility classes that manipulate another class’s data unless absolutely necessary.
  6. Consider the Class Interface
    • A class's methods should collectively form a cohesive and meaningful interface. If a method seems out of place in terms of the class's purpose, it likely belongs elsewhere.
  7. Follow Design Principles and Patterns
    • Principles like Encapsulation, Single Responsibility, and Information Hiding guide method placement.
    • Design patterns (e.g., Strategy, Observer) can help structure methods and reduce coupling.

By thoughtfully considering these principles, you can decide which methods belong to a class while keeping coupling low and cohesion high.

SDLC Project Management

Architect's Challenge when determining Coupling

Do I put this function in this object or that object? If I put it in that object, then the first object always needs to ask the second object for help. If I put it in the first object, then the first object has low cohesion. What do I do?
  • Coupling is a measure of the degree of dependency between objects. Dependency means that one object requires the data or the functionality owned by another object.
  • Loose coupling means a low degree of dependency, and tight coupling[1] means a high degree of dependency. If a change in one object requires a change in another object, the second object is dependent on the first. For example, if the interface to a server changes, the client application probably will not work. The client application depends on the server to function properly.
  1. Consequences: Coupling has a direct effect on system maintenance. Tight coupling results in a ripple effect, that is, a change in one object requires changes (or, at the very least, testing) of all the associated objects.
  2. Responsibility: Loose coupling can be achieved by assigning to an object only the behaviors that closely map to the object’s purpose (high cohesion). Avoid including behaviors simply because they are needed for a process that the object participates in.

Cohesion and Coupling: Balance is the key to Success

Cohesion and coupling should always be evaluated together. Loose coupling can be achieved easily by very low cohesion, that is, by cramming everything into one object so it does not need help from any other objects. High cohesion can result in too many tiny objects that cannot get anything done without talking to a lot of other tiny objects. The communication overhead can destroy the performance of the application. The optimum solution is a compromise between high cohesion and loose coupling. These two concepts, 1) cohesion and 2) coupling, are the enabling factors in the creation of design patterns. In a design pattern, every object has a specific responsibility, that is, high cohesion. The collection of objects has a predictable pattern of collaboration or communication. The pattern of collaboration is based on the specific nature of the coupling between the objects, that is, the help that each object requires from other objects.

Loose Tight Coupling - Exercise

Click the Exercise link below to determine instances of loose and tight coupling.
Loose Tight Coupling - Exercise

[1] tight coupling : In the Software Development Life Cycle (SDLC), tight coupling refers to a scenario where different modules or components of a software system are highly dependent on each other. This means that changes in one module are likely to require modifications in other modules, making the system less flexible and harder to maintain. Tight coupling can lead to challenges in testing, debugging, and scaling the software, as changes can have unintended consequences across the system.

SEMrush Software