logo

클래스와 팩토리 디자인 패턴

Chapter 14

56 조회

0 추천

1,430 단어

8분 예상

2024. 08. 18. 게시

2025. 02. 26. 수정

luasenvy 작성

CC BY-NC-SA 4.0

클래스

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}

클래스는 객체를 설명해둔 설계도이다. 설계도는 이름과 멤버로 구성된다. 멤버는 변수 또는 함수로 구성된다. 이 문법은 스크립트 버전이 올라가면서 추가된 것으로 이전 방식은 좀 더 지저분한 모양이었다. 간단한 프로그래밍을 위해서 굳이 찾아볼 필요는 없지만 조금 더 깊이 이해하려면 한 번 짚고 넘어가야 한다.

프로토타입 기반 언어

function Person(name, age) {
  this.name = name;
  this.age = age;
}

자바스크립트는 프로토타입 기반의 언어이다. 대단한건 아니고 프로토타입이라고 하는 매개체를 통해 객체들을 인스턴스화 하고 연관성을 맺게 한다. 클래스를 만들기 위해서는 function을 구현하는 것으로 생성이 가능하다. class 명령에 익숙하다면 벌써부터 머리가 어질어질 하겠지만 위 코드에서 구현된 function을 차근차근 뜯어보자. 파라미터와 몸체를 생성자로 사용하면 명칭, 생성자, 멤버변수 모두 갖추고 있는 class 문으로 호환이 가능하다.

prototype

인터프리터가 function Person 구문을 실행하게 되면 엔진 내부에서는 위 그림과 같이 Person 클래스와 Person 프로토타입 객체 2가지를 준비한다. 클래스에는 prototype 이라는 변수에 프로토타입 객체의 주소를 저장하고 프로토타입 객체의 constructor는 클래스의 주소를 저장하여 두 값이 서로를 바라보는 형태가 된다.

const person = new Person("luasenvy", Infinity);

new

new를 통해 클래스를 인스턴스화 하게 되면 Person 인스턴스가 생성된다. 인스턴스는 __proto__ 라고 하는 멤버에 자신의 고향인 Person 클래스의 주소를 가지고 있다.

Person.prototype.whatYourName = function () {
  return this.name;
}

const person = new Person("luasenvy", Infinity);
person.whatYourName(); // luasenvy

자바스크립트는 멤버를 class 내부에 함께 선언하는 다른 언어들과는 조금 다르다. Person 인스턴스에서 whatYourName() 함수를 호출하면 __proto__ 멤버를 참조하여 Person 클래스를 찾고 다시 클래스에서 생성자를 참조하여 Person 프로토타입을 찾는다. 최종적으로 Person 프로토타입에 선언한 whatYourName 함수가 실행된다. 이렇게 참조값을 통하여 구성되어 있기 때문에 선언 시점이 비교적 자유롭다. 예를 들면 prototype.whatYourName 멤버를 구현하는 코드를 new Person() 보다 뒤에 위치시켜도 문제없이 작동한다.

Object 클래스

Object Class

사실 앞에서 설명할 때 생략한 부분이 하나 있다. 바로 자바스크립트의 모든 객체는 Object 클래스를 상속 받는다는 점이다. 이 클래스는 엔진에 내장된 기본 클래스로 모든 객체들은 이 클래스를 최상위 클래스로 상속하고 있다. 이 또한 참조값으로 프로토타입의 __proto__ 변수에 저장된다.1

Array

예를 들어 const arr = [];와 같이 배열을 하나 만들게 되면 배열 인스턴스는 내부적으로 위 사진같은 관계도를 가지게 된다. 이러한 연결 관계를 프로토체인이라고도 말한다. 프로토체인의 마지막은 항상 Object이다. Object도 프로토타입에 __proto__ 변수가 있는데 null이 저장되어 있다. 2. 기본 자료형을 봤다면 null도 Object로 구현된 자료형이란 사실이 혼동을 줄 수 있는데 null은 조금 특이한 케이스로 프로토체인은 여기서 완전히 끝난다고 생각하면 된다.

팩토리 디자인 패턴

class Person {
  constructor() {}
}

const instance = null;
const getInstance = () => {
  if (!instance) instance = new Person();
  return instance;
}

const a = getInstance();
const b = getInstance();

const isSame = a === b; // true

말 그대로 인스턴스를 찍어내는 공장이라 생각하면 된다. 이러한 팩토리 패턴을 구현하는 대표적인 사례는 위 예시처럼 싱글턴을 유지하기 위한 인스턴스 팩토리를 만들 때이다. 그러나 클로저#응용1-함수-팩토리에서 잠시 소개하는 함수 팩토리처럼 반드시 싱글턴을 위하여 사용할 필요는 없다. 객체의 생성을 제어하는 공장이라고 생각하면 된다.

싱글턴 패턴은 생성자가 여러번 호출되어도 최초로 생성된 인스턴스를 재활용할 수 있도록 하는 디자인 패턴으로 성능을 위한 디자인 패턴이다. 다른 언어에서는 클래스 내부에 static 멤버getInstance() 함수를 구현하고 new를 호출하는 대신에 getInstance()를 호출하여 팩토리로부터 인스턴스를 전달받는 형태로 사용하기도 한다.

전체 프로그램에서 하나의 인스턴스만 필요하고 사용성이 높아 메모리에 상주해도 될만큼 중요한 경우 사용하면 좋다. 대표적인 예로 데이터베이스 커넥션을 들 수 있다.

Footnotes

  1. 최근엔 *[[prototype]]*과 같이 다른 접근방식도 제공한다. Object.prototype.__proto__을 확인하면 더 자세히 볼 수 있다.