You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Imagine that you have a toy that only does one thing, like a remote control car that only drives. This car only has to worry about driving well. In programming, a class should do one thing and do it well, just like the car.
// Each class should have a single responsibility.// Wrong: The class is doing more than one thing.classUserWrong{constructor(publicname: string,publicemail: string){}getUserName(): string{returnthis.name;}getUserEmail(): string{returnthis.email;}saveToDatabase(){// save database}}// Right: Separate responsibilities into different classes.classUser{constructor(publicname: string,publicemail: string){}getUserName(): string{returnthis.name;}getUserEmail(): string{returnthis.email;}}classUserRepository{saveToDatabase(user: User){// save database}}
O pen/Closed Principle
Think of a game of building blocks. You can add new blocks to create new things, but you don't need to break the blocks you've already built. In programming, this means that we can add new functionality without changing what's already working.
// Software should be open for extension, but closed for modification.// Wrong: We need to modify the class to add new functionality.classRectangleWrong{constructor(publicwidth: number,publicheight: number){}area(): number{returnthis.width*this.height;}}classAreaCalculatorWrong{calculateArea(shape: any): number{if(shapeinstanceofRectangle){returnshape.area();}return0;}}// Right: We added new functionality without modifying existing code.interfaceShape{area(): number;}classRectangleimplementsShape{constructor(publicwidth: number,publicheight: number){}area(): number{returnthis.width*this.height;}}classCircleimplementsShape{constructor(publicradius: number){}area(): number{returnMath.PI*this.radius*this.radius;}}classAreaCalculator{calculateArea(shape: Shape): number{returnshape.area();}}
L iskov Substitution Principle
Imagine that you have a toy that can be replaced with another similar one without any problems, like swapping a toy car for a toy truck. In programming, this means that we can replace a class with another that does something similar, and everything should still work fine.
// Objects must be substitutable for their subtypes without changing the behavior of the program.// Wrong: Subclass changes superclass behavior.classBirdWrong{fly(): void{console.log("Flying");}}classPenguinWrongextendsBirdWrong{fly(): void{thrownewError("Penguins can't fly");}}// Correct: Subclass maintains the expected behavior of the superclass.abstractclassBird{abstractmove(): void;}classSparrowextendsBird{move(): void{console.log("Flying");}}classPenguinextendsBird{move(): void{console.log("Swimming");}}
I nterface Segregation Principle
Think of a remote control that has many buttons, but you only use a few. It would be better to have smaller, specific remote controls for each thing. In programming, this means that it is better to have smaller, specific interfaces than one large, complex interface.
// Clients should not be forced to rely on interfaces they do not use.// Wrong: Large interface with methods that some classes don't need.interfaceWorkerHuman{work(): void;eat(): void;}classHumanWorkerWrongimplementsWorkerHuman{work(): void{console.log("Working");}eat(): void{console.log("Eating");}}classRobotWorkerWrongimplementsWorkerHuman{work(): void{console.log("Working");}eat(): void{// Robots don't eat}}// Right: Specific interfaces for each functionality.interfaceWorkable{work(): void;}interfaceEatable{eat(): void;}classHumanWorkerimplementsWorkable,Eatable{work(): void{console.log("Working");}eat(): void{console.log("Eating");}}classRobotWorkerimplementsWorkable{work(): void{console.log("Working");}}
D ependency Inversion Principle
Imagine that instead of toys that need special parts to work, you have toys that can work with any common part. In programming, this means that classes should depend on abstractions (general ideas) rather than on specific, concrete things, so that it is easy to swap out parts.
// High-level modules should not depend on low-level modules. Both should depend on abstractions.// Wrong: The class depends on a concrete implementation.classLightBulbWrong{turnOn(): void{console.log("LightBulb on");}turnOff(): void{console.log("LightBulb off");}}classSwitchWrong{privatelightBulb: LightBulbWrong;constructor(lightBulb: LightBulbWrong){this.lightBulb=lightBulb;}operate(): void{this.lightBulb.turnOn();}}// Correct: The class depends on an abstraction.interfaceSwitchable{turnOn(): void;turnOff(): void;}classLightBulbimplementsSwitchable{turnOn(): void{console.log("LightBulb on");}turnOff(): void{console.log("LightBulb off");}}classSwitch{privatedevice: Switchable;constructor(device: Switchable){this.device=device;}operate(): void{this.device.turnOn();}}