π₯Β κ°μ²΄ μ§ν₯ νλ‘κ·Έλλ°μ 3μμ 5μμΉ
πΒ κ°μ²΄ μ§ν₯ νλ‘κ·Έλλ°μ 3μμ
1. μΊ‘μν (Encapsulation)
λ°μ΄ν°(μμ±)μ μ΄λ₯Ό λ€λ£¨λ κΈ°λ₯(λ©μλ)μ νλμ λ¨μ(κ°μ²΄ λλ ν΄λμ€)λ‘ λ¬Άκ³ , μΈλΆμμλ λ΄λΆμ ꡬ체μ μΈ κ΅¬νμ μ¨κΈ°λ κ².
- μ νμνκ°?
- λ°μ΄ν° 보νΈ: κ°μ²΄ λ΄λΆμ λ°μ΄ν°κ° μΈλΆμμ μ§μ λ³κ²½λμ§ μλλ‘ ν¨.
- μΈν°νμ΄μ€ μ 곡: μΈλΆμλ νμν κΈ°λ₯λ§ λ ΈμΆνμ¬ μ¬μ©λ²μ λ¨μνκ² λ§λ¦.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Counter {
// #countλ private νλλ‘, ν΄λμ€ μΈλΆμμ μ§μ μ κ·Όν μ μμ΄μ λ΄λΆ λ°μ΄ν° 보νΈ(μΊ‘μν)λ¨.
// '#'λ₯Ό λΆμ΄λ©΄ μΈλΆμμ μ§μ μ κ·Όν μ μλλ‘ ν¨. (ES2021λΆν° μ§μ)
#counter = 0;
// public λ©μλ: ν΄λμ€ μΈλΆμμ νΈμΆ κ°λ₯ν ν¨μλ€
// μΈλΆμ μ 곡νλ "μΈν°νμ΄μ€" μν μ ν¨.
// count κ°μ 1 μ¦κ°μν€λ λ©μλ
increment() {
this.#count++;
}
// count κ°μ λ°ννλ λ©μλ
getCount() {
return this.#count;
}
}
const counter = new Counter(); // Counter ν΄λμ€μ κ°μ²΄(μΈμ€ν΄μ€) μμ±
counter.increment; // κ°μ²΄μ public λ©μλ νΈμΆ β λ΄λΆμ #count κ°μ΄ 1 μ¦κ°
console.log(counter.getCount()); // κ°μ²΄μ public λ©μλλ₯Ό ν΅ν΄ λ΄λΆ κ° μ‘°ν β μΆλ ₯: 1
2. μμ (Inheritance)
κΈ°μ‘΄ ν΄λμ€(λΆλͺ¨ ν΄λμ€, μνΌν΄λμ€)μ νΉμ±κ³Ό κΈ°λ₯μ μ ν΄λμ€(μμ ν΄λμ€, μλΈν΄λμ€)κ° λ¬Όλ €λ°μ μ¬μ¬μ© λ° νμ₯νλ κ².
- μ νμνκ°?
- μ½λ μ¬μ¬μ©: 곡ν΅λ κΈ°λ₯μ λΆλͺ¨μ μμ±νμ¬ μ¬λ¬ μμ ν΄λμ€μμ 곡μ .
- κ³μΈ΅ ꡬ쑰 νν: βAλ Bμ΄λ€.β λΌλ κ΄κ³λ₯Ό μμ°μ€λ½κ² λͺ¨λΈλ§.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name}μ΄(κ°) μ리λ
λλ€.`);
}
}
class Dog extends Animal {
speak() {
console.log(`${this.name}μ΄(κ°) λ©λ© μ§μ΅λλ€.`);
}
}
const dog = new Dog("λ°λμ΄");
dog.speak(); // "λ°λμ΄μ΄(κ°) λ©λ© μ§μ΅λλ€."
3. λ€νμ± (Polymorphism)
κ°μ λ©μμ§(λ©μλ νΈμΆ)μ λν΄ μ¬λ¬ κ°μ²΄κ° κ°μμ λ°©μμΌλ‘ λ°μν μ μλ λ₯λ ₯. μ£Όλ‘ λ©μλ μ€λ²λΌμ΄λ©(μ¬μ μ)μ ν΅ν΄ ꡬνλ¨.
- μ νμνκ°?
- μ½λμ μ μ°μ±: λΆλͺ¨ ν΄λμ€ νμ μΌλ‘ μ¬λ¬ μμ μΈμ€ν΄μ€λ₯Ό λ€λ£° μ μμ.
- μΈν°νμ΄μ€ ν΅μΌ: λμΌν λ©μλ μ΄λ¦μΌλ‘ λ€μν ꡬνμ μ 곡νμ¬ μΌκ΄μ± μλ μ½λ μμ±.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Shape {
draw() {
console.log("λνμ 그립λλ€.");
}
}
class Circle extends Shape {
draw() {
console.log("μμ 그립λλ€.");
}
}
class Rectangle extends Shape {
draw() {
console.log("μ¬κ°νμ 그립λλ€.");
}
}
const shapes = [new Circle(), new Rectangle()];
shapes.forEach(shape => shape.draw());
// μΆλ ₯:
// "μμ 그립λλ€."
// "μ¬κ°νμ 그립λλ€."
πΒ SOLID 5μμΉ (κ°μ²΄ μ§ν₯ μ€κ³ μμΉ)
SOLIDλ μ’μ κ°μ²΄ μ§ν₯ μ€κ³λ₯Ό μν λ€μ― κ°μ§ μμΉμ λ§νλ€.
1. λ¨μΌ μ± μ μμΉ (Single Responsibility Principle, SRP)
πΌΒ ν ν΄λμ€λ ν κ°μ§ μ± μ(λλ κΈ°λ₯)λ§ κ°μ ΈμΌ νλ€.
- μ νμνκ°?
- μ½λ μ μ§λ³΄μ μ©μ΄: νλμ ν΄λμ€κ° ν κ°μ§ μν λ§ νλ―λ‘ λ³κ²½ μ μν₯μ΄ μ΅μνλ¨.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// μ μ’μ μ: ν ν΄λμ€κ° λ°μ΄ν° μ²λ¦¬μ λ‘κΉ
μ λͺ¨λ ν¨
class UserManager {
createUser(user) {
// μ¬μ©μ μμ± λ‘μ§
}
log(message) {
// λ‘κ·Έ κΈ°λ‘ λ‘μ§
}
}
// μ’μ μ: μν μ λΆλ¦¬
class UserManager {
createUser(user) {
// μ¬μ©μ μμ± λ‘μ§
}
}
class Logger {
log(message) {
// λ‘κ·Έ κΈ°λ‘ λ‘μ§
}
}
2. κ°λ°©-νμ μμΉ (Open-Closed Principle, OCP)
πΌΒ μννΈμ¨μ΄ κ΅¬μ± μμ(ν΄λμ€, λͺ¨λ λ±)λ νμ₯μλ μ΄λ €μκ³ , μμ μλ λ«ν μμ΄μΌ νλ€.
- μ νμνκ°?
- μμ μ± μ μ§: κΈ°μ‘΄μ μ λμνλ μ½λμ μμ λμ§ μμΌλ―λ‘, μλ‘μ΄ κΈ°λ₯μ μΆκ°ν λ κΈ°μ‘΄ μ½λμμ λ²κ·Έκ° μκΈΈ μνμ΄ μ€μ΄λ λ€.
- μ μ°ν νμ₯: μλ‘μ΄ κΈ°λ₯μ μΆκ°ν λ, κΈ°μ‘΄μ μ½λλ₯Ό 건λλ¦¬μ§ μκ³ μλ‘μ΄ ν΄λμ€λ₯Ό λ§λ€μ΄ κΈ°λ₯μ νμ₯ν μ μλ€.
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
// 1. κΈ°λ³Έ ν μΈ κ³μ°κΈ° (κΈ°λ³Έ λμ: ν μΈ μμ)
class DiscountCalculator {
calculate(price) {
// ν μΈ μμ β μλ κ°κ²© λ°ν
return price;
}
}
// 2. νΌμΌνΈ(%) ν μΈ μ μ±
: DiscountCalculatorλ₯Ό νμ₯νμ¬ μλ‘μ΄ κΈ°λ₯ μΆκ°
class PercentageDiscount extends DiscountCalculator {
constructor(percentage) {
super(); // λΆλͺ¨ ν΄λμ€μ μμ±μ νΈμΆ
this.percentage = percentage; // ν μΈμ¨ (μ: 10% β 10)
}
// κΈ°μ‘΄ calculate λ©μλλ₯Ό μ€λ²λΌμ΄λ©(μ¬μ μ)
calculate(price) {
// μλ κ°κ²©μμ percentageλ§νΌ ν μΈν κ°κ²© κ³μ°
return price - (price * this.percentage / 100);
}
}
// 3. κ³ μ κΈμ‘ ν μΈ μ μ±
: μμ DiscountCalculatorλ₯Ό νμ₯
class FixedDiscount extends DiscountCalculator {
constructor(amount) {
super();
this.amount = amount; // ν μΈ κΈμ‘ (μ: 15μ ν μΈ)
}
calculate(price) {
// μλ κ°κ²©μμ κ³ μ κΈμ‘ λ§νΌ ν μΈ
return price - this.amount;
}
}
// 4. ν μΈ μ μ© ν¨μ: ν μΈ μ μ±
(DiscountCalculator)μ μΈμλ‘ λ°μ κ³μ°
function applyDiscount(price, discountCalculator) {
return discountCalculator.calculate(price);
}
// μ¬μ© μμ :
const price = 100;
const noDiscount = new DiscountCalculator(); // ν μΈ μμ
const percentageDiscount = new PercentageDiscount(10); // 10% ν μΈ
const fixedDiscount = new FixedDiscount(15); // 15μ ν μΈ
console.log(applyDiscount(price, noDiscount)); // 100 μΆλ ₯
console.log(applyDiscount(price, percentageDiscount)); // 90 μΆλ ₯ (100 - 10%)
console.log(applyDiscount(price, fixedDiscount)); // 85 μΆλ ₯ (100 - 15)
3. 리μ€μ½ν μΉν μμΉ (Liskov Substitution Principle, LSP)
πΌΒ λΆλͺ¨ ν΄λμ€μ κ°μ²΄λ₯Ό μμ ν΄λμ€μ κ°μ²΄λ‘ λ체ν΄λ νλ‘κ·Έλ¨μ μ μμ μΈ λμμ΄ μ μ§λμ΄μΌ νλ€.
- μ νμνκ°?
- λ€νμ±κ³Ό μμμ μ λ’°μ±μ 보μ₯νμ¬, μ½λ μ¬μ¬μ©κ³Ό νμ₯μ΄ μ©μ΄ν΄μ§.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Bird {
fly() {
console.log("λ κ°λ‘ λ λ€");
}
}
class Eagle extends Bird {
// Eagleμ Birdλ₯Ό μμλ°μ fly()λ₯Ό κ·Έλλ‘ μ¬μ©
}
function letBirdFly(bird) {
bird.fly();
}
const eagle = new Eagle();
letBirdFly(eagle); // μ μμ μΌλ‘ "λ κ°λ‘ λ λ€" μΆλ ₯
// λ§μ½ μμ ν΄λμ€κ° λΆλͺ¨μ κΈ°λ₯μ κΉ¨λ¨λ¦°λ€λ©΄ LSP μλ°!
4. μΈν°νμ΄μ€ λΆλ¦¬ μμΉ (Interface Segregation Principle, ISP)
πΌΒ ν΄λΌμ΄μΈνΈλ μ¬μ©νμ§ μλ μΈν°νμ΄μ€μ μμ‘΄νμ§ μμμΌ νλ―λ‘, νΉμ ν΄λΌμ΄μΈνΈμ λ§κ² μΈν°νμ΄μ€λ₯Ό λΆλ¦¬ν΄μΌ νλ€.
- μ νμνκ°?
- λΆνμν λ©μλ ꡬν κ°μλ₯Ό νΌνκ³ , ν΄λΌμ΄μΈνΈκ° νμν κΈ°λ₯λ§ μ¬μ©νλλ‘ ν¨.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// μ μ’μ μ: νλμ κ°μ²΄μ λ무 λ§μ μν μ λΆμ¬
class MultiFunctionPrinter {
print() { /* ... */ }
scan() { /* ... */ }
fax() { /* ... */ }
}
// μ’μ μ: μν μ λ°λΌ μΈν°νμ΄μ€(κΈ°λ₯)λ₯Ό λΆλ¦¬
class Printer {
print() { /* ... */ }
}
class Scanner {
scan() { /* ... */ }
}
5. μμ‘΄ μμ μμΉ (Dependency Inversion Principle, DIP)
πΌΒ κ³ μμ€ λͺ¨λ(λΉμ¦λμ€ λ‘μ§)μ μ μμ€ λͺ¨λ(μΈλΆ ꡬν)μ μμ‘΄νμ§ μκ³ , λ λ€ μΆμν(μΈν°νμ΄μ€)μ μμ‘΄ν΄μΌ νλ€.
- μ νμνκ°?
- μ μ°μ± ν₯μ: κ³ μμ€ λͺ¨λμ΄ κ΅¬μ²΄μ μΈ μ μμ€ κ΅¬νμ μμ‘΄νμ§ μμΌλ©΄, μ μμ€ λͺ¨λμ λ³κ²½νκ±°λ κ΅μ²΄ν λ κ³ μμ€ λͺ¨λμ μμ ν νμκ° μλ€.
- μ¬μ¬μ©μ± μ¦κ°: μΆμνμ μμ‘΄νλ©΄ λ€μν ꡬ체 ν΄λμ€(μ μμ€ λͺ¨λ)λ₯Ό μ½κ² κ΅μ²΄ν μ μλ€. μλ₯Ό λ€μ΄, λ‘κΉ λ°©λ²μ λ³κ²½ν λ κ³ μμ€ μ½λ(μ: μ¬μ©μ μλΉμ€)λ λ³κ²½ μμ΄ μλ‘μ΄ λ‘κ±°λ§ μ£Όμ νλ©΄ λ¨.
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
// 1. μΆμν μν μ νλ Logger "μΈν°νμ΄μ€"
// μ€μ λ‘λ μΆμ ν΄λμ€μ²λΌ λμνλ€κ³ μκ°νλ©΄ λΌ.
class Logger {
log(message) {
// μ€μ ꡬνμ νμ ν΄λμ€μμ μ 곡ν΄μΌ ν¨.
throw new Error("log() λ©μλλ ꡬνλμ΄μΌ ν©λλ€.");
}
}
// 2. μ μμ€ λͺ¨λ: μ½μμ λ‘κ·Έλ₯Ό μΆλ ₯νλ ꡬ체μ μΈ Logger ꡬν
class ConsoleLogger extends Logger {
log(message) {
console.log("ConsoleLogger:", message);
}
}
// 3. κ³ μμ€ λͺ¨λ: μ¬μ©μ κ΄λ ¨ λ‘μ§μ λ΄λΉνλ UserService
// μ΄ ν΄λμ€λ ꡬ체μ μΈ λ‘κ±°(ConsoleLogger)μ μμ‘΄νμ§ μκ³ , LoggerλΌλ μΆμνμ μμ‘΄ν¨.
class UserService {
// μμ±μμμ Logger(μΆμν)λ₯Ό μ£Όμ
λ°μ.
constructor(logger) {
// loggerλ λ°λμ Logger νμ
(λλ Loggerλ₯Ό ꡬνν κ°μ²΄)μ΄μ΄μΌ ν¨.
this.logger = logger;
}
createUser(user) {
// μ¬μ©μ μμ± λ‘μ§ (μ: λ°μ΄ν°λ² μ΄μ€ μ μ₯ λ±)
// ...
// μμ±λ ν λ‘κ·Έ κΈ°λ‘
this.logger.log(`μ¬μ©μ ${user} μμ±λ¨`);
}
}
// 4. μ¬μ© μμ
// μ¬κΈ°μ ConsoleLoggerλ₯Ό μμ±νκ³ , UserServiceμ μ£Όμ
(μμ‘΄μ± μ£Όμ
)ν¨.
const logger = new ConsoleLogger();
const userService = new UserService(logger);
// UserServiceλ λ΄λΆμμ μ΄λ€ ꡬ체 λ‘κ±°λ₯Ό μ¬μ©νλμ§ λͺ°λΌλ, λ¨μ§ logger.log()λΌλ μΆμνλ μΈν°νμ΄μ€λ§ μ¬μ©ν¨.
userService.createUser("Alice"); // μΆλ ₯: "ConsoleLogger: μ¬μ©μ Alice μμ±λ¨"
| νλͺ© | μ€λͺ | μμ μ½λ λΆλΆ |
|---|---|---|
| μΆμν (μΈν°νμ΄μ€) | κ³ μμ€ λͺ¨λκ³Ό μ μμ€ λͺ¨λ λͺ¨λκ° μμ‘΄νλ κ³μ½. ꡬ체 ꡬν μμ΄ κΈ°λ₯μ νλ§ μ μ | class Logger { log(message) { ... } } |
| μ μμ€ λͺ¨λ | ꡬ체μ μΈ κ΅¬νμ λ΄λΉνλ ν΄λμ€. μΆμνμ λ°λΌ ꡬνλ¨ | class ConsoleLogger extends Logger { ... } |
| κ³ μμ€ λͺ¨λ | ν΅μ¬ λΉμ¦λμ€ λ‘μ§μ μννλ©°, μΆμνμλ§ μμ‘΄νλ ν΄λμ€ | class UserService { constructor(logger) { ... } } |
μΆμν(Abstraction)λ 볡μ‘ν μμ€ν μ΄λ κ°μ²΄μμ νμν ν΅μ¬ κΈ°λ₯λ§ λ ΈμΆνκ³ , μΈλΆ ꡬνμ κ°μΆλ κ°λ μ΄λ€.
μΆμνμ λͺ©μ : μ¬μ©μ(κ°λ°μ)κ° λ³΅μ‘ν λ΄λΆ λμμ μ κ²½ μ°μ§ μκ³ , κ°λ¨ν μΈν°νμ΄μ€(μ¬μ©λ²)λ§ λ³΄κ³ μ¬μ©ν μ μκ² λ§λλ κ².
μμ: μλμ°¨λ₯Ό μ΄μ ν λ, μ΄μ μλ μμ§ λ΄λΆμ 볡μ‘ν μλ μ리λ₯Ό λͺ°λΌλ ν€λ₯Ό λ리면 μ°¨κ° μΆλ°νλ κ²κ³Ό κ°λ€. μ¬κΈ°μ βμλ κ±ΈκΈ°βκ° μΆμνλ μΈν°νμ΄μ€κ³ , λ΄λΆ μμ§ λ©μ»€λμ¦μ κ°μΆ°μ§ μΈλΆ μ¬νμ΄λ€.
λ: μΆμνλ μΊ‘μνλ λκ° λ¬λΌ κ·Έλ¬λ©΄
GPT:
| κ΅¬λΆ | μΆμν (Abstraction) | μΊ‘μν (Encapsulation) |
|---|---|---|
| λͺ©μ | νμν κΈ°λ₯λ§ λ ΈμΆνμ¬ μ¬μ©μκ° λ³΅μ‘ν λ΄λΆ ꡬνμ λͺ°λΌλ λκ² ν¨. | λ°μ΄ν°μ λ©μλλ₯Ό νλλ‘ λ¬Άκ³ , λ΄λΆ μνλ₯Ό μ¨κΉμΌλ‘μ¨ λ³΄νΈν¨. |
| κ΄μ | μ¬μ©μ μ μ₯: βμ΄λ»κ² μ¬μ©ν΄μΌ νλκ°?β (μΈν°νμ΄μ€ μ 곡) | ꡬνμ μ μ₯: βλ΄λΆ λ°μ΄ν°λ₯Ό μμ νκ² κ΄λ¦¬νκ³ , λ³κ²½μ μ νβ |
| μμ | μλμ°¨μ μλ λ²νΌ (μμ§ λ΄λΆ μλ μ리λ μ¨κΉ) | μν κ³μ’: μμ‘μ μν μμ€ν μ κ°μΆκ³ , μ μΆκΈμ μ ν΄μ§ μΈν°νμ΄μ€λ§ μ¬μ© |
- μΆμνλ βμ΄λ€ κΈ°λ₯(μΈν°νμ΄μ€)μ μ 곡ν κ²μΈκ°βμ μ§μ€νλ κ°λ
- μΊ‘μνλ βμ΄λ»κ² λ΄λΆ λ°μ΄ν°λ₯Ό 보νΈνκ³ , μΈλΆμ μ κ·Όμ μ νν κ²μΈκ°βμ μ΄μ μ λ κ°λ
πΒ μμ½
| μμΉ | μλ―Έ λ° λͺ©μ | μλ°μ€ν¬λ¦½νΈ μμ |
|---|---|---|
| λ¨μΌ μ± μ μμΉ (SRP) | ν ν΄λμ€λ νλμ μ± μλ§ κ°μ ΈμΌ ν¨ | UserManagerμ Loggerλ₯Ό λΆλ¦¬ |
| κ°λ°©-νμ μμΉ (OCP) | κΈ°μ‘΄ μ½λλ₯Ό μμ νμ§ μκ³ κΈ°λ₯ νμ₯μ΄ κ°λ₯ν΄μΌ ν¨ | Discount ν΄λμ€λ₯Ό νμ₯νμ¬ μλ‘μ΄ ν μΈ μ μ± μΆκ° |
| 리μ€μ½ν μΉν μμΉ (LSP) | μμ ν΄λμ€λ λΆλͺ¨ ν΄λμ€ λμ μ¬μ©λμ΄λ λ¬Έμ μμ΄μΌ ν¨ | Bird ν΄λμ€μ Eagle, letBirdFly ν¨μ μ¬μ© |
| μΈν°νμ΄μ€ λΆλ¦¬ μμΉ (ISP) | ν΄λΌμ΄μΈνΈλ λΆνμν λ©μλμ μμ‘΄νμ§ μλλ‘ μΈν°νμ΄μ€λ₯Ό λΆλ¦¬ν΄μΌ ν¨ | MultiFunctionPrinter λμ Printer, Scanner λΆλ¦¬ |
| μμ‘΄ μμ μμΉ (DIP) | κ³ μμ€ λͺ¨λμ μ μμ€ λͺ¨λμ μμ‘΄νμ§ μκ³ , μΆμνμ μμ‘΄ν΄μΌ ν¨ | UserServiceκ° Logger μΆμνμ μμ‘΄ |