클래스와 객체지향 프로그래밍 – TypeScript에서 클래스 사용법 (14강)
**TypeScript**는 **객체지향 프로그래밍(OOP)**을 지원하는 강력한 기능을 제공합니다. 그 중에서 **클래스(class)**는 객체지향 프로그래밍의 핵심 개념으로, 재사용 가능하고 관리 가능한 코드를 작성하는 데 중요한 역할을 합니다. 이번 강의에서는 **TypeScript에서 클래스 사용법**과 **객체지향 프로그래밍**의 기본 개념을 살펴보고, 이를 TypeScript에서 어떻게 적용할 수 있는지 알아보겠습니다.
객체지향 프로그래밍(OOP) 개요
**객체지향 프로그래밍(OOP)**은 프로그램을 객체라는 단위로 구성하고, 이 객체들이 서로 상호작용하면서 프로그램을 완성하는 방식입니다. OOP의 주요 특징은 다음과 같습니다:
- 캡슐화(Encapsulation): 객체의 상태(속성)와 동작(메서드)을 하나의 단위로 묶어 외부에서 직접 접근하지 못하게 보호하는 개념
- 상속(Inheritance): 부모 클래스의 속성과 메서드를 자식 클래스가 상속받아 재사용하는 개념
- 다형성(Polymorphism): 동일한 메서드가 다른 클래스에서 다르게 동작하도록 구현하는 개념
- 추상화(Abstraction): 복잡한 시스템을 간단하게 표현하기 위해 불필요한 세부 사항을 숨기는 개념
TypeScript는 이러한 객체지향 프로그래밍의 개념을 지원하며, **클래스**를 통해 코드의 구조를 보다 명확하고 효율적으로 작성할 수 있습니다.
TypeScript에서 클래스 사용법
TypeScript에서 클래스는 **`class`** 키워드를 사용하여 정의할 수 있습니다. 클래스는 객체를 생성하기 위한 **청사진**으로, 클래스 내부에 **속성**과 **메서드**를 정의할 수 있습니다.
1. 클래스 정의와 생성자(Constructor)
클래스를 정의할 때, 클래스 내부에 **속성**(프로퍼티)과 **메서드**를 정의할 수 있으며, 클래스의 인스턴스를 만들기 위한 **생성자(constructor)**를 사용할 수 있습니다. 생성자는 클래스가 인스턴스화될 때 자동으로 호출되는 특수한 메서드입니다.
class Person {
// 속성 정의
name: string;
age: number;
// 생성자 정의
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// 메서드 정의
greet() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
// 인스턴스 생성
const person1 = new Person("John", 30);
person1.greet(); // "Hello, my name is John and I am 30 years old."
위 예제에서는 **Person**이라는 클래스를 정의하고, 생성자에서 **name**과 **age**를 인자로 받아 초기화합니다. 이후 **greet** 메서드를 통해 인사하는 기능을 구현합니다. **new Person("John", 30)**으로 클래스를 인스턴스화하고, **greet()** 메서드를 호출하여 객체의 속성값을 출력할 수 있습니다.
2. 접근 제어자 (Access Modifiers)
TypeScript에서는 클래스 속성과 메서드에 접근 제어자를 사용할 수 있습니다. 기본적으로 TypeScript는 **public**, **private**, **protected**와 같은 접근 제어자를 지원합니다. 이를 통해 객체의 속성이나 메서드에 대한 접근을 제한하거나 허용할 수 있습니다.
- public: 기본 접근 제어자. 모든 클래스 외부에서 접근 가능합니다.
- private: 클래스 외부에서 접근할 수 없으며, 오직 해당 클래스 내부에서만 접근 가능합니다.
- protected: 해당 클래스와 이를 상속한 클래스에서만 접근 가능합니다.
class Employee {
public name: string;
private salary: number;
protected department: string;
constructor(name: string, salary: number, department: string) {
this.name = name;
this.salary = salary;
this.department = department;
}
// public 메서드
getSalary() {
return this.salary;
}
}
const emp = new Employee("Jane", 5000, "Engineering");
console.log(emp.name); // "Jane"
console.log(emp.salary); // 오류 발생: private 속성 접근 불가
위 예제에서 **salary** 속성은 **private**로 선언되어 외부에서 접근할 수 없습니다. 반면, **name**은 **public**으로 선언되어 외부에서 접근이 가능합니다. **getSalary** 메서드를 통해 **private** 속성에 접근할 수 있습니다.
3. 상속(Inheritance)
TypeScript의 클래스는 **상속(Inheritance)**을 지원합니다. 이를 통해 부모 클래스의 속성과 메서드를 자식 클래스에서 재사용할 수 있습니다. 자식 클래스는 부모 클래스의 기능을 상속받고, 필요에 따라 **오버라이드**(메서드 재정의)할 수 있습니다.
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
makeSound() {
console.log(`${this.name} makes a sound.`);
}
}
class Dog extends Animal {
constructor(name: string) {
super(name); // 부모 클래스 생성자 호출
}
makeSound() {
console.log(`${this.name} barks.`);
}
}
const dog = new Dog("Rex");
dog.makeSound(); // "Rex barks."
위 예제에서 **Dog** 클래스는 **Animal** 클래스를 상속받고 있습니다. **super(name)**을 사용하여 부모 클래스의 생성자를 호출하며, **makeSound** 메서드를 오버라이드하여 **Dog** 클래스에서 다른 동작을 수행하도록 합니다. 결과적으로 **Rex**는 "barks"라는 소리를 냅니다.
4. 추상 클래스(Abstraction)
**추상 클래스(abstract class)**는 직접 인스턴스를 생성할 수 없는 클래스로, 다른 클래스가 이를 상속받아 구체적인 구현을 해야 합니다. 추상 클래스는 **추상 메서드**를 포함할 수 있으며, 이 메서드는 자식 클래스에서 반드시 구현해야 합니다.
abstract class Shape {
abstract area(): number;
display() {
console.log("Displaying the shape.");
}
}
class Circle extends Shape {
radius: number;
constructor(radius: number) {
super();
this.radius = radius;
}
area() {
return Math.PI * this.radius * this.radius;
}
}
const circle = new Circle(5);
console.log(circle.area()); // 78.53981633974483
**Shape**는 추상 클래스이고, **area**는 추상 메서드입니다. **Circle** 클래스는 **Shape**를 상속받아 **area** 메서드를 구현해야만 인스턴스를 생성할 수 있습니다. 이를 통해 **추상화**를 구현할 수 있습니다.
TypeScript에서 객체지향 프로그래밍 활용하기
**객체지향 프로그래밍(OOP)**은 코드의 재사용성, 유지보수성, 확장성을 높이는 데 중요한 패러다임입니다. TypeScript에서는 클래스와 객체지향 프로그래밍의 핵심 개념을 활용하여, 더 안정적이고 효율적인 코드를 작성할 수 있습니다. 이번 강의를 통해 TypeScript에서 **클래스**, **상속**, **추상 클래스**, **접근 제어자** 등의 개념을 익히고, 객체지향 프로그래밍을 효과적으로 적용할 수 있기를 바랍니다.
마무리: 객체지향 프로그래밍의 중요성
**객체지향 프로그래밍(OOP)**은 복잡한 시스템을 구조적으로 관리하고, 코드를 효율적으로 확장할 수 있는 매우 중요한 패러다임입니다. TypeScript에서는 클래스를 활용하여 객체지향 프로그래밍을 손쉽게 구현할 수 있으며, 타입 시스템 덕분에 더욱 안전한 코드 작성이 가능합니다. 다음 강의에서는 **TypeScript에서 인터페이스와 제네릭**을 활용하여 더욱 강력한 코드 구조를 만드는 방법을 배워보겠습니다.