Design Principles
A good software design organizes the code in a way that it is "easy to understand, change, maintain and reuse."
Design principles are practical pieces of advice (guidelines) that are applied to designing or writing code to make the code more maintainable, flexible, and/or extensible.
The Commandments of OO Programming, cohesion and low coupling, are examples of design principles.
The SOLID design principles are the best known design principles in OO software development.
Single Responsbility Principle (SRP)
A class should have one, and only one, reason to change.
The more responsibilitities a class has, the more reasons it has to has to change. Every time you make a change, you risk breaking other parts of the code that you didn't intend to change. A class ideally should have a single responsibility
Cohesion is another name for SRP. Highly conehsive means you are obeying SRP.
Open-Closed Principle
Classes should be open for extension but closed for modification.
Design your application in a way to keep existing code from breaking when you implement new features.
- open to extension means you can add new features
- Closed to modification means the existing code does not need to be modified when you added the new features
In other words, new functionality does not require a rewrite of existing code.
Liskov Substitution Principle
When extending a class, consider that you should be able to pass objects of the subclass in place of objects of the parent class without breaking the client code.
Every subclass should be substitutable for their base class, i.e., a subclass should not break the expectation (code contracts) set by its super-class.
LSP is all about well-designed inheritance. It cannot substitute your base class with a subclass without things going wrong, then it means you used inheritance incorrectly.
- consider using composition over inheritance.
Interface Segregation Principle
A class that implements an interface shouldn't be forced to implement methods it does not use.
Essentially, an interface should describe one set of behaviors. Keep interfaces small, break down "fat" interfaces into several more refined interfaces.
- The goal is to reduce the adverse effect of required change by splitting software into multiple, independent parts.
By following this principle, you prevent bloated interfaces that define methods for multiple responsbilities.
Dependency Inversion Principle
High level classes shouldn't have to change because low-level classes change.
- High-level classes would be the first point of entry to the system (like user interface).
- Low-level classes would be the components that high-level classes interact with to do their job (fulfill their behavior).
- If these low level classes change, then nothing would change because the functionality would remain the same.
Often implementation involves using an interface so that both the high-level and low-level classes depend on the interface (an abstraction). The dependency inversion principle does not just change the direction of the modules by introducing an abstraction between them. In the end, you get two dependencies that both depend on the abstractions.
Linked from Object-Oriented Software Engineering