ES6 부터 JavaScript에서 class 문법을 지원하게 되었다. 그러면서 JavaScript로도 객체지향 프로그래밍을 하기 수월해졌다. (이전에는 생성자 함수와 prototype으로 구현하였다.)
그렇지만, 여전히 Java와 같은 언어 만큼 객체지향을 지원한다고 할 수 없다. 이를테면, JavaScript에서는 추상 클래스와 추상 메소드를(abstract) 문법적으로 지원하지 않는다. 그럼에도 JavaScript 기본 문법을 활용하여 추상 클래스와 추상 메소드를 구현할 수 있는 방법을 알아보자.
추상 메소드와 추상 클래스의 개념
먼저 추상 클래스와 추상 메소드의 개념에 대해 알아보자.
- 추상 메소드란 부모 클래스에서 정의하며, 자식 클래스에서 반드시 오버라이딩해야만 사용할 수 있는 메소드를 말한다. 그러므로 추상 메소드는 구현부가 없고, 선언부만이 존재한다.
- 추상 클래스는 추상 메소드를 하나 이상 포함한 클래스이며, 정의되지 않은 추상 메소드를 포함하고 있으므로, 인스턴스를 생성할 수 없다. 그러므로 상속만이 가능하다.
핵심을 정리하자면,
- 추상 메소드는 반드시 오버라이딩 되어야만 사용 가능하다.
- 추상 클래스는 인스턴스를 생성할 수 없고, 상속만 가능하다.
class Animal {
constructor(name) {
this.name = name;
}
move() {
console.log('동물이 움직입니다');
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
}
일반적인 JavaScript 클래스 문법이다. Animal은 "동물"을 의미하는데, "동물"이라는 생명은 존재하지 않고, 추상적인 관념이므로, 추상 클래스라고 볼 수 있다. new Animal()로 인스턴스를 생성할 일은 없을 것이고, 그래서는 안 된다.
그런데, 위 코드 하에서 무리없이 가능하다. 또한, 모든 동물은 move 할 것이므로, 자식 클래스는 move 메소드를 필수적으로 정의하고 사용했으면 좋겠다. 아무런 문법을 추가하지 않고는, Dog 클래스에서 move를 불러와 사용할 수 있다.
JavaScript에서 위에서 요약한 2가지 제약을 가해보자.
- 추상 메소드는 반드시 오버라이딩 되어야만 사용 가능하다.
- 추상 클래스는 인스턴스를 생성할 수 없고, 상속만 가능하다.
추상 클래스 구현
먼저 2번은 이와 같이 구현해볼 수 있다.
class Animal {
constructor(name) {
this.name = name;
if (this.constructor === Animal) {
throw new Error("추상 클래스로 인스턴스를 생성하였습니다.");
}
}
move() {
console.log('동물이 움직입니다');
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
}
const animal = new Animal("동물"); // this.constructor === [class Animal]
const dog = new Dog("개"); // this.constructor === [class Dog extends Animal]
this.constructor는 부모 클래스 명을 return 한다. 그러므로 Animal을 인스턴스로 생성하면, [class Animal]가 되고, Dog를 인스턴스로 생성하면 [class Dog extends Animal]가 된다. 이를 이용하여 Animal을 인스턴스로 생성하면 Error를 호출한다.
추상 메소드 구현
다음으로 추상 메소드가 오버라이딩 되지 않고는 사용이 불가능하도록 해보자.
class Animal {
constructor(name) {
this.name = name;
if (this.constructor === Animal) {
throw new Error("추상 클래스로 인스턴스를 생성하였습니다.");
}
}
move() {
throw new Error("추상 메소드는 꼭 오버라이딩 되어야 합니다.");
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
move() {
console.log("웕 웕");
}
}
const dog = new Dog("개");
dog.move();
이처럼 추상 메소드에서 Error를 던져준다. 그러면, 자식 클래스에서 move를 오버라이딩하지 않고 사용하면 Error가 호출될 것이다.
move를 재정의한 후에야 move를 사용할 수 있다.
부족한 점
추상 메소드는 본디, 자식 클래스로 하여금 필수적으로 구현하도록 하는 것에 의미가 있다.
하지만, 위 방법으로 추상 메소드를 구현하지 않아도 에러를 내지 않고, 추상 메소드를 구현하지 않고 호출했을 때 에러를 낸다는 점에서 완벽하게 구현한 것은 아니다.
'Script > JavaScript' 카테고리의 다른 글
[JavaScript] Chapter 37. 자바스크립트의 private (0) | 2023.03.30 |
---|---|
[JavaScript] Chapter 36. 고차 함수와 콜백(Callback) – 일급 객체란 (0) | 2023.02.07 |
[JavaScript] Chapter 35. 일반 함수 vs 익명 함수 (0) | 2023.01.26 |
[JavaScript] Chapter 34. 맵 객체(Map Object) (0) | 2023.01.16 |
[JavaScript] Chapter 33. 객체 복사하기 - 앝은 복사, 깊은 복사 (0) | 2023.01.16 |
댓글