These principles are the hard-won product of decades of experience in software engineering. They are not the product of a single mind, but they represent the integration and writings of a large number of software developers and researchers. Although they are presented here as principles of object-oriented design, they are really special cases of long-standing principles of software engineering.
There are five principles of class design
(SRP) The Single Responsibility Principle
A class should have one, and only one, reason to change.
(If a change to the business rules causes a class to change, then a change to the database schema, GUI, report format, or any other segment of the system should not force that class to change. )
(OCP) The Open/Closed Principle
Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.
(LSP) The Liskov Substitution Principle
Derived classes must be usable through the base class interface without the need for the user to know the difference.
"Why is this principle important?"
1. Because if not, then class hierarchies would be a mess. Mess being that whenever a subclass instance was passed as parameter to any method, strange behavior would occur.
2. Because if not, unit tests for the superclass would never succeed for the subclass.
(DIP) The Dependency Inversion Principle
Abstractions should not depend upon details. Details should depend upon abstractions.
High level modules should not depend upon low level modules. Both should depend upon abstractions.
We wish to avoid designs which are:
1. Rigid (Hard to change due to dependencies. Especially since dependencies are transitive.)
2. Fragile (Changes cause unexpected bugs.)
3. Immobile (Difficult to reuse due to implicit dependence on current application code.)
(ISP) The Interface Segregation Principle
Many client specific interfaces are better than one general purpose interface.
The dependency of one class to another one should depend on the smallest possible interface.
There are three principles of package cohesion
(REP) The Reuse/Release Equivalence Principle
The granule of reuse is the same as the granule of release. Only components that are released through a tracking system can be effectively reused. This granule is the package.
This means that in order to effectively reuse code it must arrive in a complete, black-box, package that is to be used but not changed. Users of the code are shielded from changes to it because they can choose when to integrate changes from the package into their own code. While this supports code ownership, and even promotes it, it does not enforce it.
(CCP) The Common Closure Principle
Classes that change together, belong together.
Classes within a released component should share common closure. That is, if one needs to be changed, they all are likely to need to be changed. What affects one, affects all.
This is the way Robert Martin puts it. I am tempted to say that it's the other way around -- classes that share common closure should be found in the same released component. The difference is that, while all classes that share closure are found in the same component, an individual pair of classes within a component aren't constrained to share closure with each other. The Common Reuse Principle gives us a reason to collect groups of classes that don't share physical closure with each other into the same component.
This principle tries to pull classes that are tightly coupled to each other together into the same package.
(CRP) The Common Reuse Principle
Classes that aren't reused together should not be grouped together.
The classes in a package are reused together. If you reuse one of the classes in a package, you reuse them all.
There are three principles of package coupling
(ADP) The Acyclic Dependencies Principle
The dependency structure for released components must be a directed acyclic graph. There can be no cycles.
The dependency structure between packages must not contain cyclic dependencies.
Different principle: Reduce cyclic dependencies as much as reasonable. I've found observers are often useful in doing this.
(SDP) The Stable Dependencies Principle
Dependencies between released categories must run in the direction of stability. The dependee must be more stable than the depender.
The dependencies between packages should be in the direction of the stability of the packages. A package should only depend upon packages that are more stable than it is.
"Stable" roughly means "hard to change", whereas "instable" means "easy to change".
(SAP) The Stable Abstractions Principle
The more stable a class category is, the more it must consist of abstract classes. A completely stable category should consist of nothing but abstract classes.
Packages that are maximally stable should be maximally abstract. Unstable packages should be concrete. The abstractness of a package should be in proportion to its stability.