GRASP Explained

GRASP Principles in Software Design: A Detailed Guide

The GRASP (General Responsibility Assignment Software Patterns) principles are foundational concepts in object-oriented design, providing guidelines for assigning responsibilities to classes and objects. Developed and first described by Craig Larman in his seminal book "Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development," these principles are designed to help create software that is robust, maintainable, and scalable. The GRASP acronym underscores the focus on solving specific problems in software design.

1. Information Expert

The principle of Information Expert suggests assigning a responsibility to the class that has the necessary information to fulfill it.

C#
      // Incorrect: Responsibility assigned to a class without the necessary information
      public class Order
      {
          // Order data
      }
      
      public class PaymentSystem
      {
          public void ProcessPayment(Order order)
          {
              // Calculate total, process payment
          }
      }
          
C#
      // Correct: Responsibility assigned to the class that has the necessary information
      public class Order
      {
          public void ProcessPayment()
          {
              // Calculate total, process payment using order data
          }
      }
          

2. Low Coupling

Low Coupling involves minimizing the dependencies between classes to increase stability and flexibility.

C#
      // Incorrect: High coupling between classes
      public class OrderManager
      {
          private Inventory inventory;
          private PaymentProcessor paymentProcessor;
      
          public void ProcessOrder()
          {
              inventory.UpdateStock();
              paymentProcessor.ProcessPayment();
          }
      }
          
C#
      // Correct: Reduced coupling enhances flexibility and maintainability
      public class OrderManager
      {
          public void ProcessOrder(Inventory inventory, PaymentProcessor paymentProcessor)
          {
              inventory.UpdateStock();
              paymentProcessor.ProcessPayment();
          }
      }
          

3. High Cohesion

High Cohesion means keeping classes focused and manageable by limiting their responsibilities.

C#
      // Incorrect: Class doing too many tasks
      public class UserManager
      {
          public void CreateUser() { }
          public void UpdateUser() { }
          public void LogUserActivity() { }
          public void GenerateUserReports() { }
      }
          
C#
      // Correct: Each class has a single focused responsibility
      public class UserManagement
      {
          public void CreateUser() { }
          public void UpdateUser() { }
      }
      
      public class UserReporting
      {
          public void LogUserActivity() { }
          public void GenerateUserReports() { }
      }
          

4. Creator

The Creator principle advises that a class should be responsible for creating instances of objects if it aggregates or contains objects of that class.

C#
      // Incorrect: Object creation is not handled by the most logical class
      public class Application
      {
          public void Start()
          {
              Order order = new Order();  // Application should not create Order directly
          }
      }
      
      public class OrderManager
      {
          // Manages orders
      }
          
C#
      // Correct: The class that contains or aggregates objects should create them
      public class OrderManager
      {
          public Order CreateOrder()
          {
              return new Order();  // OrderManager creates Order instances
          }
      }
          

5. Controller

The Controller principle suggests that you should assign the responsibility of handling system events to a class that represents the overall system or a use-case scenario, rather than to a UI class or data class.

C#
      // Incorrect: UI class handling business logic
      public class OrderForm
      {
          public void SubmitOrder()
          {
              // Handle order submission logic
          }
      }
          
C#
      // Correct: A separate controller class handles the business logic
      public class OrderController
      {
          public void SubmitOrder()
          {
              // Handle order submission logic
          }
      }
          

6. Polymorphism

Polymorphism advises using object types to drive behavior variations. This principle is used to handle alternatives based on type, often seen with overriding or implementing methods in subclasses or interfaces.

C#
      // Incorrect: Using conditional statements to handle variations
      public class Shape
      {
          public string Type;
      
          public void Draw()
          {
              if (Type == "Circle")
              {
                  // Draw circle
              }
              else if (Type == "Square")
              {
                  // Draw square
              }
          }
      }
          
C#
      // Correct: Using polymorphism to handle variations
      public abstract class Shape
      {
          public abstract void Draw();
      }
      
      public class Circle : Shape
      {
          public override void Draw()
          {
              // Draw circle
          }
      }
      
      public class Square : Shape
      {
          public override void Draw()
      {
              // Draw square
          }
      }