Software Engineering Principles
SOLID is an acronym for five design principles intended to make object-oriented designs more understandable, flexible, and maintainable. The principles are a subset of many principles promoted by Robert C. Martin first introduced in his 2000 paper Design Principles and Design Patterns.
Single Responsibility Principle (SRP)
Each Responsibility == Reason to change.
“Each class should only have one reason to change.” – Uncle Bob
Changes also affect depending classes. Possible failing behavior of depending classes (to be tested). In compiled programming languages, depending classes have to be recompiled unnecessarily after changes.
Classes that do more than one thing are difficult to reuse.
An violation of the SRP could be class Rectangle
which does some geometrical calculation and can also draw itself in a graphical application.
Applying the SRP results in two classes, one is used by GeometryApplication
, the other by GraphicalApplication
.
Open-Closed Principle (OCP)
A module should be open for extensions, but closed for modifications.
Principle ensures extensions of components without changing the source code of the specific component. This is realized by applying polymorphism.
Encapsulation of volatile and non-volatile Code. Code can be added in the volatile part while the abstract core of the application remains untouched.
Liskov Substitution Principle (LSP)
This principles was invented by Barbara Liskov in 1987.
It says: Type T’ is a Subtype of T, if objects of Type T can be exchanged by objects of Type T’ without any limitations.
Simple Example: A driver of a BMW shouldn‘t be surprised, if he tries to drive a VW. (Since both are cars and should work in kind of the same way, when trying to interact with similar functions.)
Common Violation:
Is a rectangle a square?
A solution can be found here.
Interface Segregation Principles (ISP)
Covers the drawbacks of broadly defined interfaces.
**Problem: ** Dependency of the calling object to methods, which it does noz need to know because it isn‘t using them. Changes to an interface are concerning every object knowing that interface.
Dynamic languages, like python are not affected.
example:
Dependency Inversion Principle (DIP)
- High-level modules should not depend on low-level modules. Both should depend on abstractions.
- Abstractions should not depend upon details. Details should depend upon abstractions.
But: If a concrete class is not going to change very often, and no other similar derivatives are going to be created, it does very little harm to depend on it.
example:
Button
directly depends on Lamp
, which means Button
can only be reused together with Lamp
.
Solution: Introducing an interface ButtonServer
, which belongs to the button. Lamp
derives from this interface. With that the dependency is inverted: Button
no longer depend on Lamp
, but Lamp
depends on ButtonServer
.