SOLID Principles

Lovingly Plagiarized Prepared

by Ryan Haugh

Why They're Important

  • Creates Test Seams
  • Improves Readability
  • Improves Maintainability

Single Responsibility Principle

A class should only do one thing

Single Responsibility Principle

class Customer
{
    public void Add()
    {
        try
        {
            // Logic goes here
        }
        catch (Exception ex)
        {
            System.IO.File.WriteAllText(@"C:\Error.txt", ex.ToString());
        }
    }
}

Single Responsibility Principle

What if we want to change our logging implementation?

Single Responsibility Principle

class Customer
{
    private readonly ILogger _logger;
    
    public Customer(ILogger logger)
    {
        _logger = logger;
    }
    
    public void Add()
    {
        try
        {
            // Logic goes here
        }
        catch (Exception ex)
        {
            _logger.error(ex.ToString());
        }
    }
}

Open-Closed Principle

Software entities (classes, methods, etc.) should be open for extension, but closed for modification

Open-Closed Principle

class Customer
{
    public int CustType { get; set; }

    public decimal CalculateSalePrice(decimal subtotal)
    {
        if (CustType == 1)
        {
            return subtotal * 0.90;
        }
        else
        {
            return subtotal * 0.95;
        }
    }
}

Open-Closed Principle

What if we want to add a new customer type?

Open-Closed Principle

class Customer
{
    public virtual decimal CalculateSalePrice(decimal subtotal)
    {
        return subtotal;
    }
}

class SilverCustomer : Customer
{
    public override decimal CalculateSalePrice(decimal subtotal)
    {
        return subtotal * 0.95;
    }
}

class GoldCustomer : Customer
{
    public override decimal CalculateSalePrice(decimal subtotal)
    {
        return subtotal * 0.90;
    }
}

Liskov Substitution Principle

Subtypes must be substitutable for their base types

Liskov Substitution Principle

class Inquiry : Customer
{
    public override decimal CalculateSalePrice(decimal subtotal)
    {
        return subtotal * 0.95;
    }

    public override void Add()
    {
        throw new NotImplementedException();
    }
}

Single Responsibility Principle

What if we want to iterate over a list of customers and add them to our system?

List<Customer> customers = new List<Customer>();

customers.Add(new SilverCustomer());
customers.Add(new GoldCustomer());
customers.Add(new Inquiry());

foreach (Customer customer in customers)
{
    customer.Add();
}

Liskov Substitution Principle

interface IDiscount {
    decimal CalculateSalePrice(decimal subtotal);
}

interface IPersistence {
    void Add();
}

class Inquiry : IDiscount {
    public decimal CalculateSalePrice(decimal subtotal) {
        return subtotal * 0.95;
    }
}

class Customer : IDiscount, IPersistence {
    public virtual void Add() {
        // Logic goes here
    }

    public virtual decimal CalculateSalePrice(decimal subtotal) {
        return subtotal;
    }
}

Interface Segregation Principle

Clients should not be forced to depend upon interfaces that they do not use

Interface Segregation Principle

interface IBird
{
    void Eat();

    void Walk();

    void Chirp();

    void Fly();
}

Interface Segregation Principle

What about an ostrich?

Interface Segregation Principle

interface IBird
{
    void Eat();

    void Walk();

    void Chirp();
}

interface IFlyingBird : IBird
{
    void Fly();
}

Dependency Inversion Principle

High level modules should not depend upon low level modules.

Rather, both should depend upon abstractions.

Dependency Inversion Principle

class Car
{
    private BasicEngine _engine;
    private BasicSteeringWheel _steeringWheel;
    
    public Car ()
    {
        _engine = new BasicEngine();
        _steeringWheel= new BasicSteeringWheel();
    }
}

Single Responsibility Principle

What if we want to swap out the engine and steering wheel?

Single Responsibility Principle

class Car
{
    private IEngine _engine;
    private ISteeringWheel _steeringWheel;
    
    public Car (IEngine engine, ISteeringWheel steeringWheel)
    {
        _engine = engine;
        _steeringWheel = steeringWheel;
    }
}

class BasicEngine : IEngine {}
class SuperFastEngine : IEngine {}

class BasicSteeringWheel: ISteeringWheel {}
class SuperDeluxeSteeringWheel: ISteeringWheel {}

Car basicRide = new Car(new BasicEngine(), new BasicSteeringWheel());
Car fancyRide = new Car(new SuperFastEngine(), new SuperDeluxeSteeringWheel());

The End

SOLID Principles

By Ryan Haugh

SOLID Principles

  • 1,122