OOP의 4가지 특징(캡슐화, 추상화, 상속, 다형성)
1. 캡슐화(Encapsulation)
데이터와 코드를 외부에서 알지 못하도록 하여 보호한다.
외부에서는 오직 public이나 protected 레벨로 공개된 객체나 메서드만 호출할 수 있으며, 내부 내용은 알지 못한다.
내부에 선언된 변수의 경우 getter/setter를 활용해서 접근할 수 있게 한다.
2. 추상화(Abstraction)
여러 객체들의 공통적인 속성과 메서드만를 정의해놓는 것이다.
하나의 속성이라도 abstract 키워드가 있으면 abstract class가 되어야한다.
추상 클래스(abstract class)내에 abstract 키워드로 정의된 메서드는 하위 클래스에서 반드시 구현해야하는 메서드임을 명시하는 것이다. 클래스의 틀을 정의해놓는다.
코드를 유지보수하기 좋다.
abstract class Animal {
private name:string;
constructor(name: string){
this.name = name;
}
abstract eat(): void;
abstract run(): void;
sleep() {
console.log('sleep');
};
}
class Dog extends Animal {
constructor(name: string) {
super(name);
}
eat() {}
run() {}
}
const dog = new Dog('doggy');
dog.sleep();
그리고 abstract class로는 인스턴스를 생성할 수 없다.
그럼 abstract과 interface의 차이는 무엇일까?
interface Animal {
name:string;
eat(): void;
run(): void;
sleep(): void;
}
class Dog implements Animal {
name: string;
constructor(name: string) {
this.name = name;
}
eat() {}
run() {}
sleep() {}
}
const dog = new Dog('doggy');
dog.sleep();
const dog2: Animal = {
name: '',
eat(){},
run(){},
sleep(){},
}
dog2.sleep();
위에서 확인할 수 있듯이 interface에서는 메서드를 정의하지 못하고, 오직 형태만 언급할 수 있다. 하지만 Type처럼 사용할 수 있으며 dog2에서처럼 직접 객체를 생성할 수도 있다.
추상 클래스는 공통적인 기본 기능은 미리 구현해두고, 상속을 통해 하위 클래스가 나머지 메서드를 정의할 수 있게 한다.
추상 클래스는 해당 클래스를 상속 받아서 하위 클래스를 생성하고 확장하는 데에 목적이 있고,
인터페이스는 메서드의 껍데기만 있고 메서드의 구현을 강제하는 데에 목적이 있다.
3. 상속(Inheritance)
상위 클래스의 기능을 하위 클래스가 사용할 수 있도록 한다. 중복 코드를 줄일 수 있고, 코드의 재사용성이 증가한다.
class Animal {
private _name: string = '';
constructor(name: string){
this._name = name;
}
get name(): string {
return this._name;
}
set name(name: string) {
this._name = name;
}
sayName() {
console.log(`This is ${this._name}`);
}
}
class Dog extends Animal {
constructor(name: string){
super(name);
}
bark(){
console.log('woof');
}
}
const dog = new Dog('doggy');
dog.sayName();
dog.bark();
class Cat extends Animal {
constructor(name: string){
super(name);
}
cry() {
console.log('meow');
}
}
const cat = new Cat('doggy');
cat.sayName();
cat.cry();
dog와 cat 인스턴스 모두 sayName이라는 메서드를 정의하지 않았지만 부모 클래스인 Animal에 정의되어있는 bark를 그대로 갖다 써도 정상적으로 작동되는 것을 확인할 수 있다.
4. 다형성(Polymorphism)
하나의 객체가 상황에 따라 여러 형태를 가질 수 있는 것을 말한다.
예를 들어 console.log()에서 이 함수는 아래처럼 파라미터의 타입이 다 다른 데이터를 어떻게 다 처리하는 것일까?
- console.log(123);
- console.log('123');
- console.log(true);
type LogType = <T>(data: T) => void;
const log:LogType = (data) => {
console.log(data);
};
타입스크립트를 예로 들면 제네릭을 사용한 다형성의 모습을 볼 수 있다. data 부분에 어느 형태의 데이터가 들어오더라도 T는 해당 데이터(data)의 타입에 맞춰서 log 함수의 call signature를 설정하고 함수를 정상 동작시키는 것을 확인할 수 있다.