I - Interface Segregation Principle (ISP)
Clients should not be forced to implement interfaces they do not use.
This means interfaces should be small and specific to the needs of the implementing class.
For Example:
❌Bad
interface Work{
eat(): void;
work(): void;
}
class Developer implements Work{
eat() {
console.log("eat");
}
work() {
console.log("work");
}
}
class Robot implements Work{
eat() {
throw new Error("eat"); // Robot does not need to inherit eat() method
}
work() {
console.log("work");
}
}
✅Good
interface Workable {
work(): void;
}
interface Eatable {
eat(): void;
}
class Developer implements Workable, Eatable {
eat() {}
work(): void {
}
}
Base on the strength of interface, one class can implement multiple interfaces. You should break the interface into smaller parts to better suit the need of your class
D - Dependency Inversion Principle (DIP)
*High-level modules should not depend on low-level modules. Both should depend on abstractions.
*
This priciple encourage the use of dependency injection
For Example:
❌Bad
class BackendDeveloper {
develop(){
console.log("Developing developer");
}
}
class FrontendDeveloper {
develop(){
console.log("FrontendDeveloper");
}
}
class Project {
backendDeveloper: BackendDeveloper;
frontendDeveloper: FrontendDeveloper;
constructor() {
this.backendDeveloper = new BackendDeveloper();
this.frontendDeveloper = new FrontendDeveloper();
}
build(){
this.backendDeveloper.develop();
this.frontendDeveloper.develop();
}
}
In the snippet of code, there are multiple problem.However, the most important problem you can see is:
- If you want to add
MobileDeveloper()
, you will need to modifyProject()
which will impact other method using it -
Project()
is tightly couple tobackendDeveloper
andfrontendDeveloper
✅Good
interface Developer {
developer(): void
}
class BackendDev implements Developer {
developer() {
console.log("Developer Developer");
}
}
class FrontendDeveloper implements Developer {
developer() {
console.log("Developer Developer");
}
}
class Project {
constructor(private developers: Developer[]) {
}
build(){
this.developers.forEach(developer => {developer.developer();});
}
}
High-level module depends on abstractions (Developer interface).
Low-level modules implement the abstraction.
Loose coupling makes it easy to extend and maintain.
Adding MobileDev:
class MobileDeveloper implements Developer {
develop() {
console.log("Writing mobile code");
}
}
// Usage
const developers: Developer[] = [
new BackendDeveloper(),
new FrontendDeveloper(),
new MobileDeveloper(), //easy to add and make it does not change in Project()
];
const project = new Project(developers);
project.build();
Thank You :)))
Top comments (0)