Single Responsibility
Class should only have one clear reason to change (one responsibility).
Open/Closed Principles
Class should be open to extension (inheritance), but closed for modification.
Liskov Substitution
Ensures subclass can substitute its superclass.
-
Parameter type of overrides should match or more abstract of
foo(Parent)to✅
foo(GrandParent)❌
foo(Child)Break if client passes
Parenttofoo, butfoois actually expectingChild, tried to access fields not available onParent -
Return type of overrides should match or subtype of
Parent foo()to✅
Child foo()❌
GrandParent foo()Breaks when client tries to access fields on
Parent, but not available onGrandParent -
Overriden shouldn’t throw more than it’s base
Breaks when additional exceptions were not expected by client, and were raised
-
Subclass shouldn’t strengthen pre conditions (increasing requirements established by superclass)
Breaks when client believes the object it’s passing satisfies the conditions set by superclass of another object, but the object is actually a subclass of the superclass that needs extra conditions
-
Subclass shouldn’t weaken post conditions (failing to uphold guarantees established by superclass)
Breaks when client expects objects that passes certain conditions, but subclass actually doesn’t satisfy it
-
Subclass should preserve Invariants of superclass
Breaks when superclass expects
studentCountto be non negative, but subclass makes it negative -
Subclass shouldn’t modify private fields of superclass
Allowing subclasses to access private fields can lead to tight coupling between the superclass and its subclasses
The superclass may enforce certain invariants through its public methods. Direct access to private fields by the subclass can bypass these checks
Interface Segregation
Break down “fat” interfaces into more specific ones. not all classes are able to satisfy a bloated interface.
Class shouldn’t be forced to conform to its interfaces.
Dependency Inversion Principle
High level should depend on abstractions. Low level should depend on abstractions
On early app development, low level classes are often developed first before high level classes. dependency inversion principle suggests changing the direction of the dependency
Where to use Dependency Inversion:
you don’t need interfaces everywhere. The rule of thumb is — if you’d ever want to swap the implementation, or test the consumer in isolation, make it a interface.

