SlideShare a Scribd company logo
Introduction to
SOLID Principles
Background
• Dependency Inversion Principle
• Single Responsibility Principle
• Open/Closed Principle
• Liskov Substitution Principle
• Interface Segregation Principle
S: Single Responsibility
Principle (SRP)
“Every class should have a single responsibility, and that
responsibility should be entirely encapsulated by that class”
Introduction to SOLID Principles
1. When we need to modify the way we save Customer data
2. When we want to revise the way we log our Exceptions
The Customer class has 2 reasons to change:
Introduction to SOLID Principles
Introduction to SOLID Principles
Difficulty in naming classes can be a sign that you are trying to do
too much, and that this class is taking on too much responsibility
Do One Thing: methods that only do one thing are usually very
short: 3-5 lines
Multiple unit tests for the same method should be a warning sign
that you are doing too much
SRP - Tips
O: Open/Closed
Principle (OCP)
“Software entities (classes, modules, functions, etc.) should be
open for extension, but closed for modification.”
O: Open/Closed
Principle (OCP)
Open for extension – you can extend an object’s behaviour
Closed for modification – without the need to modify any
existing code
Introduction to SOLID Principles
Introduction to SOLID Principles
Introduction to SOLID Principles
L: Liskov Substitution
Principle (LSP)
“If S is a subtype of T, then objects of type T may be replaced
with objects of type S without altering any of the desirable
properties of that program”
Introduction to SOLID Principles
Introduction to SOLID Principles
Introduction to SOLID Principles
Introduction to SOLID Principles
Introduction to SOLID Principles
Favour Interfaces over inheritance (Google this…you’ll find
loads!)
Use inheritance sparingly.
Keep inheritance hierarchies from getting to big – aim for no
more than two or three deep.
LSP - Tips
I: Interface Segregation
Principle (ISP)
“No client should be forced to depend on methods it does not
use.”
Introduction to SOLID Principles
Introduction to SOLID Principles
Introduction to SOLID Principles
Introduction to SOLID Principles
Introduction to SOLID Principles
Introduction to SOLID Principles
D: Dependency
Inversion Principle (DIP)
“A. High-level modules should not depend on low-level
modules. Both should depend on abstractions.
B. Abstractions should not depend on details. Details should
depend on abstractions.”
Introduction to SOLID Principles
Introduction to SOLID Principles
Introduction to SOLID Principles
Unity
Castle Windsor
IOC Containers
Introduction to SOLID Principles
Questions
Follow Us
Dave Cook
http://tech.comparethemarket.com/author/cookie/
@dcookie_1981
@thectmers

More Related Content

PPTX
Solid Principles
PDF
Solid principles
PPTX
Solid Principles
PPTX
SOLID Principles Part 2
PPTX
SOLID_Principles_Explained_Presentation.pptx
PPTX
Solid-Principles
PPTX
PPTX
Sec1_SOLID Principles_Software Engineering.pptx
Solid Principles
Solid principles
Solid Principles
SOLID Principles Part 2
SOLID_Principles_Explained_Presentation.pptx
Solid-Principles
Sec1_SOLID Principles_Software Engineering.pptx

Similar to Introduction to SOLID Principles (20)

PPTX
Principios solid con c#
PPTX
SOLID Principles principals for Programming
PPTX
Solid principles
PDF
Solid - OOD Principles
PPTX
S.O.L.I.D. Principles for Software Architects
PPTX
PDF
L22 Design Principles
PPTX
Solid principles
PDF
Understanding SOLID Principles in OOP programming
PPTX
SOLID Principles in OOPS ooooooooo.pptx
PPTX
Solid design principles
PPTX
Becoming a better developer by using the SOLID design principles
PDF
Inversion of Control
PPTX
Solid as OOP abstraction
PPTX
The Solid Principles
PPTX
GDSC - SOLID Principles session.pptx
PDF
Solid principles
PDF
Solid principle
PPTX
SOLID Principles
Principios solid con c#
SOLID Principles principals for Programming
Solid principles
Solid - OOD Principles
S.O.L.I.D. Principles for Software Architects
L22 Design Principles
Solid principles
Understanding SOLID Principles in OOP programming
SOLID Principles in OOPS ooooooooo.pptx
Solid design principles
Becoming a better developer by using the SOLID design principles
Inversion of Control
Solid as OOP abstraction
The Solid Principles
GDSC - SOLID Principles session.pptx
Solid principles
Solid principle
SOLID Principles
Ad

Recently uploaded (20)

PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
Encapsulation theory and applications.pdf
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Spectral efficient network and resource selection model in 5G networks
PPTX
MYSQL Presentation for SQL database connectivity
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PPTX
Spectroscopy.pptx food analysis technology
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
Electronic commerce courselecture one. Pdf
Agricultural_Statistics_at_a_Glance_2022_0.pdf
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
20250228 LYD VKU AI Blended-Learning.pptx
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Encapsulation theory and applications.pdf
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
The AUB Centre for AI in Media Proposal.docx
Unlocking AI with Model Context Protocol (MCP)
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Mobile App Security Testing_ A Comprehensive Guide.pdf
Per capita expenditure prediction using model stacking based on satellite ima...
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
Building Integrated photovoltaic BIPV_UPV.pdf
Spectral efficient network and resource selection model in 5G networks
MYSQL Presentation for SQL database connectivity
NewMind AI Weekly Chronicles - August'25 Week I
Spectroscopy.pptx food analysis technology
Diabetes mellitus diagnosis method based random forest with bat algorithm
Understanding_Digital_Forensics_Presentation.pptx
Electronic commerce courselecture one. Pdf
Ad

Introduction to SOLID Principles

Editor's Notes

  • #4: SOLID is an acronym
  • #5: If you think of Responsibility as a reason for change, a class should only have one reason to change, because it only does one thing. This responsibility should be entirely encapsulated by that class. In other words: do something once & Don’t Repeat Yourself (DRY)
  • #6: Example of code that violates SRP – the Add method is not only concerned with adding the Customer to the database, but also determines how and where exception messages are logged. This should be someone else’s responsibility! NB: This code also decides that the only information about the exception that is useful is the error message. All Stack Trace information or inner exceptions are ignored 
  • #7: Now you may be thinking ‘Big Deal!, that’s easy to fix!’ But if you multiply this up over the whole system, this problem really starts to stack up. Let’s say you have an E-commerce web site with classes similar to this for Customers & Addresses, Products & Product Categories, Orders, Wish Lists, Recommendations etc, each implementing their own exception handling. Now imagine that you no longer want to log exceptions to a text file but to a database of their own, or the event viewer. Because each one is responsible for what to do with an exception when something goes wrong, you would need to change each of these classes independently. This creates a lot of work, and risk – because you risk breaking the actual function of the class while you make these changes.
  • #8: In this example we follow SRP. The Customer class is responsible for Adding data to the database, and delegates responsibility of logging any exceptions to the ExceptionLogger class. The ExceptionLogger knows nothing about the Customer class, and is responsible only for logging exceptions. Now if we want to change where we write our exception messages we make the change in one place, and this cascades to all consumers of the ExceptionLogger for free.
  • #9: While we have improved our code, we are still breaking another SOLID Principle. We shall come back to this example later when we talk about the Dependency Inversion Principle.
  • #10: Worth noting these
  • #11: OK…. what does that mean?
  • #12: It would seem that these two attributes are at odds with each other. The normal way to extend the behavior of a module is to make changes to that module…right?
  • #13: Example of code that violates OCP In this scenario we want one behaviour for Standard products and a different behaviour for our Featured products. No problem – a simple If statement sorts this right out. However, if we add a new ProductType, then we need to modify how this existing code works in order to include the new ProductType. What if we add lots more ProductTypes? – We need more and more If statements. What if this is not the only thing that varies by ProductType? - We start to duplicate this If block all over our code base. NB: Don’t fool yourself into thinking that a switch statement is any better – it’s just as bad!
  • #14: The code above adheres to the OCP. We have created an abstract class (Product) to encapsulate the behaviour that varies, and two separate derivatives of this type: StandardProduct & FeaturedProduct. Each derivative is responsible for extending the behaviour of the Render method, which means that there is no need to change any existing code in order to add new types of product in the future. It also removes duplication of If blocks (or switch statements), by removing the need to test for ProductType at all. Each derivative can be unit tested in isolation, with only a few tests (rather than one for each If!).
  • #15: This code is where it all comes together: Polymorphism at work – here we see that the program is able to adapt it’s behaviour depending on the objects it is given, without the need to know or care what type of objects they are. The program simply treats them all the same, and lets the individuals deal with the orders it gives. We are now able to Render all our products; regardless of what type of product they are without the need to change any code for future derivatives This method doesn’t even need to change if we delete a derivative
  • #16: Or to put it another way… Subtypes must be substitutable for their base types Or, A subclass should only override the parent class' methods in a way that does not break functionality from a client's point of view. If Child is derived from Parent, then Parent can be replaced by Child and the program will continue to work as normal.
  • #17: Example of code that violates LSP Square is a sub class of Rectangle, but the Square object sets both the height & width to the same value when either property is changed. While this makes sense in the real world, it does mean that the Square does not behave in the same way as it’s parent class. Real World Example: Filling your car up. Petrol & Diesel are both Types of Fuel, derived from Oil. However, substituting one for the other has a dramatic side affect on the system in which it is used.
  • #18: Given that Square is a type of Rectangle in the previous sample (it inherits from Rectangle), we should be able to substitute one for the other without any impact. However, our second test here will actually fail as the calculated area is actually 16, not the expected 20. This means we can’t substitute Square for Rectangle as you would expect, because it would break our system and fill our engine with Diesel.
  • #19: To get around this, we could implement either of the two solutions above to solve the issue. They both remove the Inheritance chain, thus removing the LSP violation. However, they both mean that we can’t achieve Polymorphic behaviour, because we can’t interact with them in the same way.
  • #20: A better solution is to define a contract for interacting with our shapes (IShape); this defines a blue-print for all shapes to adhere to. Now we can interact with all shapes in the same way (Polymorphically), by working with the Interface, instead of the specific implementations of a shape.
  • #21: Which means we can now do this. Notice that is we add more and more types of shape the code to calculate total area doesn’t need to change (Open to Extension/ Closed to Modification!)
  • #23: Or to put it another way: Classes & Interfaces with a massive API suck!
  • #24: Let’s look at the following interface: IVehicle At first glance it seems fine… nothing bad going on here. Or is there?
  • #25: Lets think about when we start building concrete implementations of this interface. A Car class would be ok, as it can meet the contract set by the interface…But there is going to be a lot of code here – clearly we are going too much! (Breaking SRP!) And what about a Motorbike, or a Bus class? Neither of these need to implement all the methods required by the contract!
  • #26: We could just throw an exception whenever someone calls the methods we don’t need? No – this is dirty! This code smells! It’s a waste of time & effort, and creates lots of exception handling issues for all consumers of the class.
  • #27: A better solution would be to break the large interface down into smaller, more specific interfaces, based on responsibility. Each interface is only concerned with one responsibility (SRP – only has one reason to change)
  • #28: Because a single class can implement multiple interfaces, we are now able to pick and choose which functionality we wish to implement in each concrete implementation and we don’t need to implement functionality we don’t need in order to conform to a contract.
  • #29: However, we do have one last issue we need to resolve. Our Car class, if we actually write all the code that is required, is going to be quite large (Code Smell!) and has more than one reason to change (SRP) as it is dealing with movement, temperature controls and audio controls. This brings us to the Dependency Inversion Principle.
  • #30: You’ll be forgiven for looking at the detail here and thinking “WTF?” Lets look at a code example, as this is much simpler that the definitions above make it seem.
  • #31: Before we sort out our vehicle problems, lets demonstrate Dependency Inversion on the simpler scenario we saw back on Slide 9. The Customer class nicely delegates responsibility for logging exceptions to the ExceptionLogger class (therefore adhering to SRP). Unfortunately this code breaks the Dependency Inversion Principle, because it magically creates a instance of the ExceptionLogger internally when and instance of Customer is created. What’s wrong with that I hear you say? The problem is that we have left the responsibility for the creation & configuration of the ExceptionLogger to the Customer class, instead of allowing the consumer of the class (or the client) to decide. This is very ridged and inflexible. It means that every single instance of a Customer that is ever created will always log exceptions with the same settings: let’s say to the F: drive. So later when someone new wants to use an instance of Customer in a system that does not have an F: drive, this will fail.
  • #32: By making the following changes we delegate responsibility for the creation & configuration of our Dependencies to the consuming code. This is often referred to as Dependency Injection. Dependency Injection is very useful during TDD, as you are in control of dependant objects in the setup of the test. This makes it easier to control which code is executed inside the class under test, and therefore easily set expectations. However, there are still improvements we could make to the Customer class.
  • #33: Here we have changed the Customer class to depend on an interface IExceptionLogger instead of the concrete class ExceptionLogger. The rest of the Customer class is unchanged, but this subtle difference means that we now delegate which implementation of IExceptionLogger the Customer will use at run time to the client (in addition to the creation and configuration of that implementation). As the consumer of the Customer class, we can now use whichever IExceptionLogger we choose. The Customer class is no longer tightly coupled to the implementation of ExceptionLogger, but loosely coupled to IExceptionLogger.
  • #34: It is worth noting that once you get to the stage were you are injecting dependencies into your classes as interfaces, then you are at the stage where you can dabble in the dark arts of Inversion of Control (IOC) Containers. Examples listed above. These allow you to “resolve dependencies” automatically using configured defaults. For example: In the case of our Customer class, if I were to create a new instance of Customer without having specified which implementation of IExceptionLogger I actually wanted to use, my IOC container would simply “resolve” this dependency (work out which implementation to use) by creating an instance of whatever IExceptionLogger I had configured to be the default. You can usually make this configuration in either code or and external config file, such as xml. However, the reason I use the phrase ‘Dark Arts’ to describe IOC is because it can sometimes be hard to work out what is actually going on in your code – you can disappear down a rabbit hole trying to figure out which implementation of and interface is being used if you are not familiar with the code base. That said, they can be really powerful tools, you just need to gain some experience using them.
  • #35: If we now apply DIP to our Car class, we end up with something like this. Responsibility for the various different behaviours is abstracted out to classes that deal entirely with that behaviour, and nothing else (SRP). These could even be reused by different concrete classes. For example ExpensiveCar and Car may use the same implementation of IAudioControls. Car is loosely coupled to the Abstractions of IVehicle, IAudioControls and IHeatedSeats instead of being tied into specific classes such as BangAndOlusenSoundSystem, for example, because we are “injecting the dependencies” rather than creating instances inside our class definition.