-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsolid.ts
More file actions
162 lines (126 loc) · 3.56 KB
/
solid.ts
File metadata and controls
162 lines (126 loc) · 3.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// SOLID PRINCIPLES
/*
Fast Overview
- S: 1 class, 1 responsibility
- O: Add without modify
- L: Subclasses should behave like Superclass
- I: Prefer small interfaces over a big one
- D: Write code that depends from abstractions
*/
// ? 1. Single Responsibility Principle (SRP)
// A class should have just one responsibility (if it has more than one motive to change, ERROR)
// Wrong Example
// The class doing 2 separated actions, NOT GOOD
class ReportDefiner {
generatePdf() {}
saveToDatabase() {}
}
// Correct Example
// Each class has is own action
class ReportGenerator {
generatePdf() {}
}
class ReportOnRepo {
saveToDatabase() {}
}
// ! -----
// ? 2. Open/Closed Principle (OCP)
// A class should always be open to extension but closed to edits
// Meaning: You should add new features without modify the actual code
// Wrong Example
// To add a new payment method i should modify the actual class
class Payment {
pay(type: string) {
if (type === 'paypal') {}
else if (type == 'stripe') {}
}
}
// Correct Example
// If i want to add a new class (like ApplePay) i can create a new class without touching the others
interface PaymentMethod {
pay(): void
}
class Paypal implements PaymentMethod {
pay() {}
}
class Stripe implements PaymentMethod {
pay() {}
}
class PaymentProcessor {
process(payment: PaymentMethod) {
payment.pay()
}
}
// ! ----
// ? 3. Liskov Substitution Principle (LSP)
// The object from a derivated class could substitute the one of the parent class without breaking the code
// MEANING: subclasses should ALWAYS behave like the parent class
// Wrong Example
// A penguin can't substitute a bird without errors -> LSP violated
class ABird {
fly() { console.log("I'm flying") }
}
class APenguin extends ABird {
fly() { throw new Error("Penguins can't fly!") }
}
// Correct Example
// Separated classes and respected principle
class Bird {}
class FlyingBird extends Bird {
fly() { console.log("I'm flying")}
}
class Penguin extends Bird {
swim() { console.log("I'm swimming") }
}
// ! ----
// ? 4. Interface Segregation Principle (ISP)
// Prefer a lot of small (specific) interfaces then a big one
// Class shouldnt be forced to use non used methods
// Wrong Example
// We're using non-specific methods in the Robot class
interface AWorker {
work(): void
eat(): void
}
class ARobot implements AWorker {
work() {/* OK */}
eat() { throw new Error("Robot don't eat!")}
}
// Correct Example
interface Workable { work(): void }
interface Eatable { eat(): void }
class Human implements Workable, Eatable {
work(): void { console.log("I'm working") }
eat(): void { console.log("I'm eating") }
}
class Robot implements Workable {
work(): void { console.log("I'm a robot and i can only work") }
}
// ! ----
// ? 5. Dependency Inversion Principle (DIP)
// The code needs to depend from abstractions, not from real implementations
// High level classes should NOT depend from low level classes, but from interfaces or abstractions
// Wrong Example
// If i want to use PostgreSQL then i need to modify the class
class MySQLDatabaseWrong {
connect() { console.log("Connecting...") }
}
class AUserService {
db = new MySQLDatabaseWrong();
}
// Correct Example
// I can use what Database i want without modify UserService
interface Database {
connect(): void
}
class MySQLDatabase implements Database {
connect(): void { console.log("Connecting to SQL Database...") }
}
class PostgreSQLDatabase implements Database {
connect(): void { console.log("Connecting to PostgreSQL Database...") }
}
class UserService {
constructor(private db: Database) {
this.db = db
}
}