SOLID Principles in Swift: Real-World Examples with Code

The SOLID principles are five design principles intended to make software designs more understandable, flexible, and maintainable. Let’s explore each principle in the context of Swift, using real-world examples and code samples.

A class should have only one reason to change, meaning it should have only one job or responsibility.

Example: Managing User Authentication

Violation of SRP:

class UserManager {
    func registerUser(username: String, password: String) {
        // Code to register user
    }

    func loginUser(username: String, password: String) {
        // Code to log in user
    }

    func validateEmail(email: String) -> Bool {
        // Code to validate email
    }

    func sendWelcomeEmail(email: String) {
        // Code to send welcome email
    }
}

Adherence to SRP:

class UserRegistrationManager {
    func registerUser(username: String, password: String) {
        // Code to register user
    }
}

class UserLoginManager {
    func loginUser(username: String, password: String) {
        // Code to log in user
    }
}

class EmailValidator {
    func validateEmail(email: String) -> Bool {
        // Code to validate email
    }
}

class EmailSender {
    func sendWelcomeEmail(email: String) {
        // Code to send welcome email
    }
}

Software entities should be open for extension but closed for modification.

Example: Payment Processing

Violation of OCP:

class PaymentProcessor {
    func processPayment(method: String) {
        if method == "CreditCard" {
            // Process credit card payment
        } else if method == "PayPal" {
            // Process PayPal payment
        }
    }
}

Adherence to OCP:

protocol PaymentMethod {
    func processPayment()
}

class CreditCardPayment: PaymentMethod {
    func processPayment() {
        // Process credit card payment
    }
}

class PayPalPayment: PaymentMethod {
    func processPayment() {
        // Process PayPal payment
    }
}

class PaymentProcessor {
    func processPayment(using method: PaymentMethod) {
        method.processPayment()
    }
}

Objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program.

Example: Vehicle Hierarchy

Violation of LSP:

class Vehicle {
    func startEngine() {
        // Start engine
    }
}

class ElectricCar: Vehicle {
    override func startEngine() {
        // Cannot start engine as electric cars don't have engines
    }
}

Adherence to LSP:

class Vehicle {
    func start() {
        // Start vehicle
    }
}

class Car: Vehicle {
    override func start() {
        // Start car
    }
}

class ElectricCar: Vehicle {
    override func start() {
        // Start electric car
    }
}

Clients should not be forced to depend on interfaces they do not use.

Example: Document Management

Violation of ISP:

protocol Document {
    func printDocument()
    func faxDocument()
    func scanDocument()
}

class Printer: Document {
    func printDocument() {
        // Print document
    }

    func faxDocument() {
        // Not implemented
    }

    func scanDocument() {
        // Not implemented
    }
}

Adherence to ISP:

protocol Printable {
    func printDocument()
}

protocol Faxable {
    func faxDocument()
}

protocol Scannable {
    func scanDocument()
}

class Printer: Printable {
    func printDocument() {
        // Print document
    }
}

class FaxMachine: Faxable {
    func faxDocument() {
        // Fax document
    }
}

class Scanner: Scannable {
    func scanDocument() {
        // Scan document
    }
}

High-level modules should not depend on low-level modules. Both should depend on abstractions.

Example: Notification System

Violation of DIP:

class EmailService {
    func sendEmail(message: String) {
        // Send email
    }
}

class NotificationManager {
    let emailService = EmailService()

    func sendNotification(message: String) {
        emailService.sendEmail(message: message)
    }
}

Adherence to DIP:


protocol NotificationService {
    func send(message: String)
}

class EmailService: NotificationService {
    func send(message: String) {
        // Send email
    }
}

class SMSService: NotificationService {
    func send(message: String) {
        // Send SMS
    }
}

class NotificationManager {
    private let service: NotificationService

    init(service: NotificationService) {
        self.service = service
    }

    func sendNotification(message: String) {
        service.send(message: message)
    }
}

Conclusion

Adhering to the SOLID principles in Swift helps create a codebase that is more modular, maintainable, and scalable. By applying these principles, you can build robust applications that are easier to understand, extend, and modify.

— End —

Our Service:

Looking for the best mobile app development courses in Ramanathapuram? Learn Mobile App is your premier training center for mastering iOS, Android, React Native, Flutter, and Mobile App Automation. Our expert instructors provide hands-on training, ensuring you gain practical skills in mobile app development. Whether you’re interested in iOS, Android, React Native, Flutter, or Mobile App Automation, Learn Mobile App in Ramanathapuram offers comprehensive courses to elevate your career. Visit our website now to enroll in the top courses at Learn Mobile App in Ramanathapuram and secure your future in mobile app development.