Introduction to SOLID principles
Video: Introduction to SOLID principlesI'm going to go through the five principles of Object-Oriented Design that are grouped under the acronym SOLID. These were put together by the author Robert Martin, also known as Uncle Bob. First, a word of warning: the names of these principles can sound excessively complex, the meanings behind them are not quite so bad. S is for the Single Responsibility Principle; O, the Open/Closed Principle; L, the Liskov Substitution Principle; I is the Interface Segregation Principle; and D is the Dependency Inversion Principle.
Viewers: in countries Watching now:
Most modern programming languages, such as Java, C#, Ruby, and Python, are object-oriented languages, which help group individual bits of code into a complex and coherent application. However, object-orientation itself is not a language; it's simply a set of ideas and concepts.
Let Simon Allardice introduce you to the terms—words like abstraction, inheritance, polymorphism, subclass—and guide you through defining your requirements and identifying use cases for your program. The course also covers creating conceptual models of your program with design patterns, class and sequence diagrams, and unified modeling language (UML) tools, and then shows how to convert the diagrams into code.
- Why use object-oriented design (OOD)?
- Pinpointing use cases, actors, and scenarios
- Identifying class responsibilities and relationships
- Creating class diagrams
- Using abstract classes
- Working with inheritance
- Creating advanced UML diagrams
- Understanding object-oriented design principles
Introduction to SOLID principles
I'm going to go through the five principles of Object-Oriented Design that are grouped under the acronym SOLID. These were put together by the author Robert Martin, also known as Uncle Bob. First, a word of warning: the names of these principles can sound excessively complex, the meanings behind them are not quite so bad. S is for the Single Responsibility Principle; O, the Open/Closed Principle; L, the Liskov Substitution Principle; I is the Interface Segregation Principle; and D is the Dependency Inversion Principle.
Now, before you run screaming from the room, I will say that the concepts behind most of these are much easier to recall than the names, and it's not about remembering the names of these principles, that's really not important. So let's take them one by one. First, the Single Responsibility Principle. An object should have one primary responsibility, one reason to exist, and that reason entirely encapsulated within one class. It can have multiple behaviors, but all those behaviors are oriented around that core reason for existence, and everything it does should support that.
So one of the impacts here is we don't create God objects that take the place of several real world business entities, and neither do we split one focus concept's behavior across multiple objects. An object should always be responsible for itself. Next, we have the O, the Open/Closed Principle-- open for extension but closed to modification. And we're talking about software entities here, classes, modules, functions. What this means is that after you've written some working code, and then your requirements change, if you need to add additional behavior, you do it by writing new code, not by changing all code that already works.
One example is with Inheritance. Say we have some working code, and then we get a new business requirement, we can support it by adding a new class, and if that class needs some additional behavior we don't change the original superclass, we provide some new code. So we're not changing the existing code that already works, our system is open for extension, but closed for modification. L is for the Liskov Substitution Principle. What this means is objects in a program should be replaceable with instances of their subtypes--their subclasses or derived classes--without altering the correctness of the program.
It's an extension of that whole inheritance idea. Meaning that if we've created a whole bunch of derived classes or child classes or subclasses--whatever term you prefer to use for them--I should always be able to pass any of these around and treat them like their superclass, their parent class. I should never have the situation where we say, oh yes, we can do any of them except that one, that one has to be treated specially. If that's the case, it sounds like it's not a true subclass, and it's breaking this principle.
I is for the Interface Segregation Principle. The idea that many specific interfaces are better than one general purpose interface. Now, we're not talking here about user interfaces, but the Java style interfaces we talked about earlier in the course, also known as Protocols. The idea of having formalized lists of method names that a class can choose to support and implement. But the principle here is that interfaces, those lists of methods should be as small as possible.
And if they start to get bigger, they should be split up into smaller interfaces. Because classes can choose to implement multiple smaller interfaces, no class should be forced to support huge lists of methods that it doesn't need. And finally, the D, the Dependency Inversion Principle, depend on abstractions, not on concretions. Now, that sounds very vague, and this is often the toughest one of the five to grasp. What it describes is the value of not directly tying concrete objects together but making them deal with abstractions in order to minimize dependencies between our objects. Here is an example.
Let's say we have a store object, and our store allows people to buy digital audio files to download. So when we do, the store object is going to read the file using a very specialized class called AudioFileReader, and then writing it out using another very specialized class called AudioFileWriter. So the Store object, which we can consider a high-level object is very dependent on these two low-level objects that deal with the specifics of reading and writing this audio file. Now, the Dependency Inversion Principle means that we would like to disconnect these two very concrete classes.
So what I would do is remove those connections, and I'd insert a new layer here, which might be an abstract class that represents a Reader and Writer rather than something very specific like an AudioFileReader and an AudioFileWriter. So now the Store class is not dependent on the concrete AudioFileWriter and AudioFileReader, but on abstractions. We have this new layer of abstraction here. And the benefit of that is that we can now have flexibility to say these low-level classes could be any class that inherits from those abstract classes of Reader and Writer.
Perhaps MovieFileReader and MovieFileWriter, or later on, GameFileReader and GameFileWriter, or whatever else may come along. So it allows substitutions, flexibility going forward, being able to replace and extend without--in this case-- changing the Store object at all. However, do be aware that if you've got too many layers to try and future-proof your code, it can be argued that you're violating you ain't gonna need it rule, so something to bear in mind.
Now, as you can tell, these are principles that I might be able to summarize in a few minutes, but they could take years to appreciate how they would be applied in a variety of different situations. And you won't always be able to follow them, nor will you always want to, and nor are you intended to. These aren't rules, they aren't dogma, they are useful guidelines. SOLID can be viewed as a checklist, like using FURPS at the early stages of functional requirements, not necessarily something you'd expect to memorize, but certainly something worth revisiting now and again to prompt you in creating a concise and a well-made class design.
There are currently no FAQs about Foundations of Programming: Object-Oriented Design.