Solid Principles

Solid Principles

Solid Principles are the time tested principles for writing clean and high quality code in object oriented programming.

Why should you study SOLID Principles?

Studying the SOLID principles is essential for software developers because they provide a clear framework for designing software that's easy to maintain, scalable, and resilient against bugs. You will find a major difference in your code quality once you learn these principles as they are time tested.

Single responsibility in pseudocode refers to the principle that each module or class within the code should have only one responsibility or task to fulfill. This ensures that the code remains focused and easy to understand, test, and maintain. Here's an example of pseudocode with a single responsibility:


class Calculator:
function add(a, b):
return a + b

function subtract(a, b):
return a - b

function multiply(a, b):
return a * b

function divide(a, b):
if b != 0:
return a / b
else:
throw Exception("Cannot divide by zero.")

class FileHandler:
function read(file):
// code to read from the specified file

function write(file, data):
// code to write data to the specified file
```

In the above pseudocode, the `Calculator` class is responsible for performing basic arithmetic operations. It has separate functions for addition, subtraction, multiplication, and division, ensuring that each function has a single responsibility.

Similarly, the `FileHandler` class is responsible for handling file operations. It has functions for reading from a file and writing data to a file, again adhering to the principle of single responsibility.

By ensuring that each module or class has a single responsibility, the code becomes more modular, maintainable, and easier to comprehend.

Code Example

Without Single Responsibility Principle

Class UserManager {
    Properties: username, email

    // Method responsible for user creation logic.
    // Violation: Incorporates user validation and initialization, which is a separate concern from the core functionality of managing user data.
    Method CreateUser() {
        // Logic to create a user
    }

    // Method responsible for saving data to a database.
    // Violation: Manages database interactions, an entirely different responsibility from user creation or user management, indicating a breach of SRP.
    Method SaveToDatabase() {
        // Logic to save user to the database
    }
}

// Usage:
userManager = new UserManager('JohnDoe', 'john@example.com')

// UserManager class is doing more than one operation, handling both user creation and saving data to the database.
userManager.CreateUser()  // This should ideally be the responsibility of a 'UserCreator' class.
userManager.SaveToDatabase()  // This operation should be delegated to a dedicated 'DatabaseManager' class.

// Here, the UserManager class violates the Single Responsibility Principle by taking on responsibilities that should be handled by separate classes.
// This design intertwines unrelated functionalities, making the system harder to maintain, test, and extend.

With Single Responsibility Principle


// Defining a 'User' class that is only responsible for maintaining user information.
// It does not handle responsibilities beyond storing the data that defines a user.
Class User {
    Properties: username, email
    // Possibly more properties defining a user, but no methods manipulating those or handling other logic.
}

// 'UserCreator' class is solely responsible for the logic behind creating a user.
// This separation adheres to SRP as it's only tasked with ensuring the correct creation of a user object.
Class UserCreator {
    Method CreateUser(user) {
        // Logic to create a user
        // This includes all the checks and initializations necessary for establishing a valid user.
        // No concern with how the user object is stored or used beyond creation logic.
    }
}

// 'UserDatabase' class is dedicated only to handling the database interactions for a user object.
// It doesn't need to know the user creation logic; its sole responsibility is to save the user object.
Class UserDatabase {
    Method SaveUser(user) {
        // Logic to save user to the database
        // This could include connecting to the database, structuring data, handling exceptions, etc.
        // No understanding of user object creation or other business logic is necessary here.
    }
}

// Demonstrating usage of the classes, each with their single responsibility, in a workflow.

// Creating a 'User' object, which is only concerned with data storage.
user = new User('JohnDoe', 'john@example.com')

// 'UserCreator' is used to initialize and potentially validate a new user, ensuring it adheres to business rules.
userCreator = new UserCreator()
userCreator.CreateUser(user)

// 'UserDatabase' handles the saving of the user object, abstracting away the specifics of database interaction.
userDatabase = new UserDatabase()
userDatabase.SaveUser(user)

// In this flow, each class and method has its own distinct responsibility, adhering to the Single Responsibility Principle.
// This makes the code more maintainable and modular, reducing the complexity of each component and making debugging and testing easier.
Implementing Single Responsibility Principle (SRP) in pseudocode involves following these key points:

1. Identify the Responsibilities: Clearly define the different responsibilities of a class or module.

2. Separate Responsibilities: Ensure that each responsibility is handled by a separate class or module.

3. Define Interface: Define an interface or contract for each class or module that specifies the methods and properties it provides.

4. Delegate Responsibly: If a responsibility requires collaboration with other classes or modules, delegate the specific tasks to the appropriate classes.

5. Limit Dependencies: Minimize the dependencies between classes by only relying on the necessary interfaces and not directly accessing the internal implementation details of other classes.

The pseudocode example below illustrates the implementation of SRP:

```plaintext
Class Order {
var items = []

// Add an item to the order
function addItem(item) {
items.append(item)
}

// Calculate the total price of the order
function calculateTotalPrice() {
var total = 0
for each item in items {
total += item.price
}
return total
}
}

Class Item {
var name
var price

// Constructor for creating an item
constructor(name, price) {
this.name = name
this.price = price
}
}

function main() {
// Create an order
var order = new Order()

// Add items to the order
var item1 = new Item("Item 1", 10)
var item2 = new Item("Item 2", 20)
order.addItem(item1)
order.addItem(item2)

// Calculate and print the total price of the order
var totalPrice = order.calculateTotalPrice()
print("Total Price: " + totalPrice)
}
```

In the above pseudocode, the `Order` class is responsible for managing the items in an order and calculating the total price. The `Item` class encapsulates the details of an individual item. This separation of responsibilities allows for better modularity and maintainability in the codebase, as each class handles its specific responsibility independently.
Common mistakes while implementing single responsibility in pseudocode:
1. Overloading a function or class with multiple responsibilities.
2. Creating dependencies between different functions or classes that should be independent.
3. Not clearly defining the responsibility of each function or class.
4. Not considering extensibility and maintainability while implementing single responsibility.

Best practices while implementing single responsibility in pseudocode:
1. Clearly define the responsibility of each function or class.
2. Keep the functions or classes focused on a single task or responsibility.
3. Create independent functions or classes, reducing dependencies.
4. Avoid having too many parameters or attributes in a function or class.
5. Use meaningful names for functions, classes, and variables that accurately describe their responsibility.
6. Ensure each function or class has a clear input and output, making it easier to test and understand its purpose.
7. Consider future changes and design the code in a way that allows for easy modifications and extensibility.

SolidPrinciples is a website dedicated to SOLID Principles. We want to ensure developers really the understand SOLID Principles and understand how to apply them in their code. It is both beginner and intermediate level friendly.

SolidPrinciples

SolidPrinciples © 2024 All rights reserved.

email
email
email