Skip to content

S.O.L.I.D. Principles

S ingle Responsibility Principle

// Each class should have a single responsibility.

// Wrong: The class is doing more than one thing.
class UserWrong {
	constructor(
		public name: string,
		public email: string
	) {}

	getUserName(): string {
		return this.name;
	}

	getUserEmail(): string {
		return this.email;
	}

	saveToDatabase() {
		// save database
	}
}

// Right: Separate responsibilities into different classes.
class User {
	constructor(
		public name: string,
		public email: string
	) {}

	getUserName(): string {
		return this.name;
	}

	getUserEmail(): string {
		return this.email;
	}
}

class UserRepository {
	saveToDatabase(user: User) {
		// save database
	}
}

O pen/Closed Principle

// Software should be open for extension, but closed for modification.

// Wrong: We need to modify the class to add new functionality.
class RectangleWrong {
	constructor(
		public width: number,
		public height: number
	) {}

	area(): number {
		return this.width * this.height;
	}
}

class AreaCalculatorWrong {
	calculateArea(shape: any): number {
		if (shape instanceof Rectangle) {
			return shape.area();
		}
		return 0;
	}
}

// Right: We added new functionality without modifying existing code.
interface Shape {
	area(): number;
}

class Rectangle implements Shape {
	constructor(
		public width: number,
		public height: number
	) {}

	area(): number {
		return this.width * this.height;
	}
}

class Circle implements Shape {
	constructor(public radius: number) {}

	area(): number {
		return Math.PI * this.radius * this.radius;
	}
}

class AreaCalculator {
	calculateArea(shape: Shape): number {
		return shape.area();
	}
}

L iskov Substitution Principle

// Objects must be substitutable for their subtypes without changing the behavior of the program.

// Wrong: Subclass changes superclass behavior.
class BirdWrong {
	fly(): void {
		console.log("Flying");
	}
}

class PenguinWrong extends BirdWrong {
	fly(): void {
		throw new Error("Penguins can't fly");
	}
}

// Correct: Subclass maintains the expected behavior of the superclass.
abstract class Bird {
	abstract move(): void;
}

class Sparrow extends Bird {
	move(): void {
		console.log("Flying");
	}
}

class Penguin extends Bird {
	move(): void {
		console.log("Swimming");
	}
}

I nterface Segregation Principle

// Clients should not be forced to rely on interfaces they do not use.

// Wrong: Large interface with methods that some classes don't need.
interface WorkerHuman {
	work(): void;
	eat(): void;
}

class HumanWorkerWrong implements WorkerHuman {
	work(): void {
		console.log("Working");
	}

	eat(): void {
		console.log("Eating");
	}
}

class RobotWorkerWrong implements WorkerHuman {
	work(): void {
		console.log("Working");
	}

	eat(): void {
		// Robots don't eat
	}
}

// Right: Specific interfaces for each functionality.
interface Workable {
	work(): void;
}

interface Eatable {
	eat(): void;
}

class HumanWorker implements Workable, Eatable {
	work(): void {
		console.log("Working");
	}

	eat(): void {
		console.log("Eating");
	}
}

class RobotWorker implements Workable {
	work(): void {
		console.log("Working");
	}
}

D ependency Inversion Principle

// High-level modules should not depend on low-level modules. Both should depend on abstractions.

// Wrong: The class depends on a concrete implementation.
class LightBulbWrong {
	turnOn(): void {
		console.log("LightBulb on");
	}

	turnOff(): void {
		console.log("LightBulb off");
	}
}

class SwitchWrong {
	private lightBulb: LightBulbWrong;

	constructor(lightBulb: LightBulbWrong) {
		this.lightBulb = lightBulb;
	}

	operate(): void {
		this.lightBulb.turnOn();
	}
}

// Correct: The class depends on an abstraction.
interface Switchable {
	turnOn(): void;
	turnOff(): void;
}

class LightBulb implements Switchable {
	turnOn(): void {
		console.log("LightBulb on");
	}

	turnOff(): void {
		console.log("LightBulb off");
	}
}

class Switch {
	private device: Switchable;

	constructor(device: Switchable) {
		this.device = device;
	}

	operate(): void {
		this.device.turnOn();
	}
}